1/* masthead */ 2function resizeMasthead(container, header, footer) { 3 var _doc_width = $(window).width(); 4 var _doc_height = $(window).height(); 5 var _width = $(container).width(); 6 var _height = $(container).height(); 7 var _header_height = $(header).outerHeight(); 8 var _footer_height = $(footer).outerHeight(); 9 10 /* masthead slideshow */ 11 $(container).css({ 12 "height": _doc_height - _header_height 13 }); 14 15 /* masthead video */ 16 $(container + '-video').css({ 17 "height": _doc_height - _header_height 18 }); 19 20 /* moves video controls, which are dynamically created by videojs */ 21 $('<style>').text('.homepage .masthead-video .video-js .vjs-control-bar { top: ' + _header_height + 'px; }').appendTo('head'); 22 /* adjust by viewport size, if needed */ 23 if ($(window).width() <= 1140) { 24 /* moves video controls, which are dynamically created by videojs */ 25 $('<style>').text('.homepage .masthead-video .video-js .vjs-control-bar { top: 0px; }').appendTo('head'); 26 } 27 28 /* video should be less tall on tablets/phones */ 29 if ($(window).width() <= 1024) { 30 $(container + '-video').css({ 31 "height": _doc_height / 2 32 }); 33 } 34} 35resizeMasthead('.masthead', 'header', 'footer'); 36 37/*Generates the elements for the mobile menu*/ 38function generateMenu(selector) { 39 var menu = $(selector).html(); 40 $("body").not('#rfp').prepend("<div id='mobile-navigation'><span class='menu' aria-expanded='false'></span>" + menu + '</div>'); 41} 42 43/* Iterates through the list of menu options and determines if the item has a submenu */ 44function itemHasChildren(item) { 45 $(item).each(function(i) { 46 if ($(this).children('ul').length) { 47 $(this).addClass('hasChildren'); 48 $(this).children('a').append('<i class="icon"></i>') 49 } 50 }); 51}; 52 53/* Adjusts the submenu position so it does not overflow into the window boundaries*/ 54function submenuPosition () { 55 var _submenu = $(this).children('ul'); 56 var _submenuWidth = _submenu.outerWidth(); 57 var _windowWidth = $(window).width(); 58 var _distance = $(window).width() - $(this).offset().left; 59 60 if (_submenuWidth > _distance - 20) { 61 _submenu.css({ 62 'left' : 'auto', 63 'right' : 0 64 }); 65 } else { 66 _submenu.css({ 67 'right' : 'auto', 68 'left' : 0 69 }); 70 } 71} 72 73/* Shows the menu items*/ 74function showMenu(menu) { 75 $(menu).addClass('show', 200); 76} 77 78/* Hides the menu items*/ 79function hideMenu(menu) { 80 $(menu).removeClass('show', 200); 81} 82 83jQuery(document).ready(function($) { 84 85 $('#searchFilter').click(function(e) { 86 var month = parseInt($('#month').val()) || 0; 87 var week = parseInt($('#week').val()) || 0; 88 var type = parseInt($('#type').val()) || 0; 89 var unit = parseInt($('#unit').val()) || 0; 90 91 if (month == 0 && week == 0 && type == 0 && unit == 0) { 92 alert('You must select an option from at least one of the search parameters to continue.'); 93 e.preventDefault(); 94 } 95 }); 96 97 $('#searchFilterRental').click(function(e) { 98 var arrival = $.trim($('#startDate').val()); 99 var departure = $.trim($('#endDate').val()); 100 101 if (arrival == '' || departure == '') { 102 alert('You must select the arrival and departure dates to continue.'); 103 e.preventDefault(); 104 } 105 }); 106 107 //Menu 108 var Navigation = { 109 menu : '#navigation', 110 menuItems : '#navigation > li', 111 mobileMenu : '#mobile-navigation > ul', 112 button : '#mobile-navigation .menu', 113 links : '#mobile-navigation > ul > li' 114 } 115 116 generateMenu(Navigation.menu); 117 itemHasChildren(Navigation.links); 118 119 120 //Hide the menu if anything but the menu is clicked 121 $('body').click(function(e) { 122 if ($(Navigation.mobileMenu).hasClass('show')) { 123 hideMenu(Navigation.mobileMenu); 124 } 125 });
126 127 $(Navigation.button).click( function(e) { 128 e.stopPropagation(); 129 //If button is clicked, hide, or else, show 130 if (!$(Navigation.mobileMenu).hasClass('show')) { 131 showMenu(Navigation.mobileMenu); 132 $(Navigation.button).attr('aria-expanded', 'true'); 133 } else { 134 hideMenu(Navigation.mobileMenu); 135 $(Navigation.button).attr('aria-expanded', 'false'); 136 } 137 e.preventDefault(); 138 }); 139 140 $(Navigation.links).click(function(e) { 141 e.stopPropagation(); 142 }); 143 144 $('#mobile-navigation a').click(function(e) { 145 var tagClicked = e.target.nodeName; 146 var parent = $(this).parent('li'); 147 var childList = parent.children('ul'); 148 var childLists = $(Navigation.links).children('ul'); 149 if (tagClicked == "I") { 150 if (!childList.hasClass('show')) { 151 childLists.not(childList).removeClass('show', 200); 152 childList.addClass('show', 200); 153 e.preventDefault(); 154 } else { 155 childList.removeClass('show', 200); 156 } 157 e.preventDefault(); 158 } 159 }); 160 161 $('.masthead .scroll').click(function(e) { 162 $("html, body").animate({ 163 scrollTop: $('.masthead').outerHeight() 164 }, 500); 165 }); 166 167 //Magnific Gallery 168 if(jQuery().magnificPopup) { 169 function accommodationsGallery(selector) { 170 var photos = []; 171 selector.each(function(i) { 172 var _url = $(this).attr('href'); 173 photos.push({src: _url}); 174 }); 175 176 return photos; 177 } 178 179 $(".magnific").each(function() { 180 $(this).magnificPopup({ 181 delegate: 'a[data-type="magnific-image"]', 182 type: 'image', 183 closeOnContentClick: false, 184 closeBtnInside: false, 185 mainClass: 'mfp-with-zoom mfp-img-mobile', 186 image: { 187 verticalFit: true, 188 titleSrc: function(item) { 189 return item.el.attr('data-title'); 190 } 191 }, 192 gallery: { 193 enabled: true 194 }, 195 zoom: { 196 enabled: true, 197 duration: 300, // don't foget to change the duration also in CSS 198 opener: function(element) { 199 return element.find('img'); 200 } 201 } 202 }); 203 }); 204 205 $('a.open-unit').each(function() { 206 $(this).magnificPopup({ 207 items: accommodationsGallery($(this).siblings('.magnific').find('a[data-type="magnific-image"]')), 208 type: 'image', 209 closeOnContentClick: false, 210 closeBtnInside: false, 211 mainClass: 'mfp-with-zoom mfp-img-mobile', 212 image: { 213 verticalFit: true, 214 }, 215 gallery: { 216 enabled: true 217 } 218 }); 219 }); 220 221 } 222 223 if(jQuery().slick) { 224 //Fades in images 225 $('.masthead img:first-child').load(function(){ 226 $('.masthead').addClass('images-loaded'); 227 }).each(function(){ 228 if(this.complete) { 229 $(this).trigger('load'); 230 } 231 }); 232 $('.hero-carousel .gallery').on('init', function(event, slick){ 233 $(".masthead").addClass('slick-loaded'); 234 }); 235 $('#testimonials-slider #testimonials').slick({ 236 infinite: true, 237 arrows: false, 238 slidesToShow: 1, 239 fade: true, 240 autoplay: true, 241 autoplaySpeed: 10000, 242 pauseOnHover: true, 243 adaptiveHeight: true 244 }); 245 $('.hero-carousel .gallery').slick({ 246 infinite: true, 247 arrows: false, 248 rows: false, 249 slidesToShow: 1, 250 fade: true, 251 dots: true, 252 autoplay: true, 253 autoplaySpeed: 6000, 254 prevArrow: '<a href="" aria-label="Previous" class="slick-prev slick-arrow"></a>', 255 nextArrow: '<a href="" aria-label="Next" class="slick-next slick-arrow"></a>', 256 pauseOnHover: true 257 }); 258 $('.special-carousel .gallery').slick({ 259 infinite: true,
260 arrows: false, 261 rows: false, 262 slidesToShow: 1, 263 fade: true, 264 dots: true, 265 autoplay: true, 266 autoplaySpeed: 6000, 267 prevArrow: '<a href="" aria-label="Previous" class="slick-prev slick-arrow"></a>', 268 nextArrow: '<a href="" aria-label="Next" class="slick-next slick-arrow"></a>', 269 pauseOnHover: true 270 }); 271 $('.carousel-gallery .slick.gallery').slick({ 272 infinite: true, 273 arrows: true, 274 rows: false, 275 slidesToShow: 4, 276 slidesToScroll: 1, 277 278 responsive: [ 279 { 280 breakpoint: 1200, 281 settings: { 282 slidesToShow: 4, 283 slidesToScroll: 1 284 } 285 }, 286 { 287 breakpoint: 780, 288 settings: { 289 slidesToShow: 3, 290 slidesToScroll: 1 291 } 292 }, 293 294 { 295 breakpoint: 480, 296 settings: { 297 slidesToShow: 2, 298 slidesToScroll: 1 299 } 300 }, 301 { 302 breakpoint: 340, 303 settings: { 304 slidesToShow: 1, 305 slidesToScroll: 1 306 } 307 }, 308 ] 309 }); 310 311 $('.photo-content-grid.rooms .item .item-photos .slick.gallery').slick({ 312 infinite: true, 313 arrows: false, 314 fade: true, 315 slidesToShow: 1, 316 dots: true, 317 autoplay: true, 318 autoplaySpeed: 6000, 319 centerMode: true, 320 pauseOnHover: true 321 }); 322 323 } 324 325 // expand collapse 326 $('#accessibility .accordion h4').click(function(event) { 327 $(this).nextUntil('h4').slideToggle('fast'); 328 $(this).toggleClass('selected'); 329 event.preventDefault(); 330 }); 331 332 // initialize the megamenu 333 $('.nav').accessibleMegaMenu(); 334 // removes role="region" which is generated by megamenu.js but not needed. 335 let navigation = document.querySelectorAll('.nav *'); 336 navigation.forEach(function(element) { 337 element.removeAttribute("role"); 338 }); 339 340 // focus css 341 $('#navigation > li').focusin(function(e) { 342 $(this).addClass('is-focused'); 343 }); 344 $('#navigation > li').focusout(function(e) { 345 $(this).removeClass('is-focused'); 346 }); 347 348 $('button.accordion').click(function(e) { 349 var content = $(this).next(); 350 var scrollheight = content.prop('scrollHeight'); 351 352 if ($(this).hasClass('is-open')) { 353 $(this).removeClass('is-open', 200); 354 content.css({'max-height':'0'}); 355 } else { 356 $(this).addClass('is-open', 200); 357 content.css({'max-height': scrollheight + 'px'}); 358 } 359 }); 360 361 // slide-in ad 362 $('#slidein').animate({ 363 right : '0px' 364 }, 1000); 365 $('#slideinClose').click(function() { 366 $('#slidein').animate({ 367 right : '-=430px' 368 }, 1000); 369 }); 370 371 372 // 373 // ADA/WCAG issue with images generated by parallax.js 374 // This resolves issues that are raised by the Axe accessibility tool 375 // AW - 2021/03/16 376 // 377 378 var parallaxMirror = '.parallax-mirror'; 379 380 // add empty alt attribute to parallax.js images 381 $(parallaxMirror + ' img').attr('alt', ''); 382 383 // add (arguably unnecessary) role and aria-label to containing div 384 $(parallaxMirror).attr('role', 'complementary'); 385 386 //the aria-label value must be unique, so add an incrementing number to the end 387 var parallaxCount = '1'; 388 $(parallaxMirror).each(function() { 389 $(this).attr('aria-label', 'Decorative Image ' + parallaxCount); 390 parallaxCount++; 391 }); 392}); 393 394 395 396 397// Map Guide - Accessibility 398// 2025-05-20 - AW 399// Improved keyboard navigation via 'Tab' focusing 400// Problem: When a user tabs through each marker within the Leaflet map and presses enter, the popup is not next in the tab sequence and the user has to continue tabbing through all other markers in order to reach the popup. This will be confusing to users with screenreaders. 401// Solution: The following code listens for when a user presses 'Enter' on their keyboard to select a specific marker within the Leaflet map. Then it will append a `role="dialog"` attribute to the popup and give it the next focus within the sequence. When a user closes the didalog then it will return focus to the previously selected marker. 402document.addEventListener('DOMContentLoaded', () => { 403 const poiMap = document.querySelector('#poi-map'); 404 if (!poiMap) { return; } 405 let lastFocusedMarker = null; 406 407 const setPopupAccessibility = (popup) => { 408 popup.setAttribute('role', 'dialog'); 409 popup.setAttribute('tabindex', '-1'); 410 411 const heading = popup.querySelector('h3'); 412 if (heading?.textContent.trim()) { 413 popup.setAttribute('aria-label', heading.textContent.trim()); 414 } 415 416 popup.focus(); 417 418 const closeBtn = popup.querySelector('.leaflet-popup-close-button'); 419 if (closeBtn) { 420 const restoreFocus = () => lastFocusedMarker?.focus(); 421 closeBtn.addEventListener('click', restoreFocus, { once: true });
422 423 popup.addEventListener('keydown', (e) => { 424 if (e.key === 'Escape') { 425 closeBtn.click(); 426 restoreFocus(); 427 } 428 }, { once: true }); 429 } 430 }; 431 432 const observer = new MutationObserver((mutations) => { 433 mutations.forEach(({ addedNodes }) => { 434 addedNodes.forEach(node => { 435 if (node.classList?.contains('leaflet-marker-icon')) { 436 node.setAttribute('tabindex', '0'); 437 438 node.addEventListener('keydown', (e) => { 439 if (e.key === 'Enter') { 440 lastFocusedMarker = node; 441 setTimeout(() => { 442 const popup = poiMap.querySelector('.leaflet-popup'); 443 if (popup) setPopupAccessibility(popup); 444 }, 50); 445 } 446 }); 447 } 448 }); 449 }); 450 }); 451 452 observer.observe(poiMap, { childList: true, subtree: true }); 453}); 454 455// ***************************************************** 456// Fix for POI previous/next navigation buttons accessibility 457// The 'poi-nav' element needs `aria-hidden="true"` if the buttons are not displayed and `aria-hidden="false"` if they are 458// ***************************************************** 459const poiPrevNextA11yFix = () => { 460 const WIDGET_SEL = '.widget'; 461 const CATEGORIES_SEL = '.widget .categories'; 462 const POINAV_SEL = '.widget .poi-nav'; 463 const PREV_SEL = '.widget .poi-nav .prev'; 464 const NEXT_SEL = '.widget .poi-nav .next'; 465 466 const widget = document.querySelector(WIDGET_SEL); 467 if (!widget) return; 468 469 // idempotent updater that always uses fresh refs 470 const updateNavAriaHidden = () => { 471 const poiNav = widget.querySelector(POINAV_SEL); 472 const poiPrev = widget.querySelector(PREV_SEL); 473 const poiNext = widget.querySelector(NEXT_SEL); 474 if (!poiNav || !poiPrev || !poiNext) return; 475 476 const anyVisible = poiPrev.classList.contains('visible') || poiNext.classList.contains('visible'); 477 // Use setAttribute with strings (ARIA is not a boolean attribute) 478 poiNav.setAttribute('aria-hidden', anyVisible ? 'false' : 'true'); 479 }; 480 481 // Initial run after DOM is ready 482 if (document.readyState === 'loading') { 483 document.addEventListener('DOMContentLoaded', updateNavAriaHidden, { once: true }); 484 } else { 485 updateNavAriaHidden(); 486 } 487 488 // Re-run after the select changes (defer to let any re-render finish) 489 const categoriesSelect = widget.querySelector(CATEGORIES_SEL); 490 if (categoriesSelect) { 491 categoriesSelect.addEventListener('change', () => { 492 // if another script re-renders with innerHTML/async, run after micro/macro task 493 queueMicrotask(updateNavAriaHidden); 494 setTimeout(updateNavAriaHidden, 0); 495 }); 496 } 497 498 // Also catch DOM replacements of .poi-nav via MutationObserver 499 const mo = new MutationObserver((mutations) => { 500 for (const m of mutations) { 501 if (m.type === 'childList') { 502 // If poi-nav was added/removed/replaced, re-apply ARIA 503 if ([...m.addedNodes, ...m.removedNodes].some(n => 504 n.nodeType === 1 && (n.matches?.(POINAV_SEL) || n.querySelector?.(POINAV_SEL)) 505 )) { 506 updateNavAriaHidden(); 507 } 508 } 509 // If classes on prev/next change, also update 510 if (m.type === 'attributes' && (m.target.matches?.(PREV_SEL) || m.target.matches?.(NEXT_SEL))) { 511 updateNavAriaHidden(); 512 } 513 } 514 }); 515 516 mo.observe(widget, { 517 subtree: true, 518 childList: true, 519 attributes: true, 520 attributeFilter: ['class'] 521 }); 522}; 523poiPrevNextA11yFix();
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.