PageSourceSearch

https://www.jhrl.com/sites/all/themes/custom/vrweb_foundation/js/vrweb_foundation.js?tlse4v

js jhrl.com collected 2026-10-06 13:18:53 UTC 33,144 bytes, 947 lines download raw bytes

1(function ($, Drupal) {
2
3  // Cross-browser safe replacement for console.log().
4  // usage: log('inside coolFunc',this,arguments);
5  // http://paulirish.com/2009/log-a-lightweight-wrapper-for-consolelog/
6  window.log = function(){
7    log.history = log.history || [];   // store logs to an array for reference
8    log.history.push(arguments);
9    if(this.console){
10      console.log( Array.prototype.slice.call(arguments) );
11    }
12  };
13
14  // We do some window resizing stuff but on mobile we actually need to listen
15  // for "onorientationchange" instead of "resize", so accomodate for both.
16  var supportsOrientationChange = 'onorientationchange' in window,
17    orientationEvent = supportsOrientationChange ? 'orientationchange' : 'resize';
18
19  // Royal Slider is hidden in css, to hide a FUBC.
20  // Reveal it when we're ready.
21  $(window).load(function() {
22    $('.js .royalSlider').css({'visibility': 'visible', 'opacity': 1});
23  });
24
25  // Resize Foundation Section tabs to make them full-width.
26  $(window).load(function() {
27    var mobile_breakpoint = 0,
28      $container = $('.section-container');
29
30    if ($container.length) {
31      $(window).on(orientationEvent, $.throttle(250, function() {
32        if ($(window).width() > mobile_breakpoint) {
33          $container.each(function() {
34            var $title = $container.find('p.title'),
35              length = $title.length;
36
37            if (length) {
38              $title.each(function() {
39                // Float rounded to precision 2
40                var w = parseFloat(100 / length).toFixed(2),
41                  $t = $(this),
42                  l = w * $t.parents('section').index();
43
44                $t.css({'width' : w + '%', 'left' : l + '%'});
45              });
46            }
47          });
48        }
49      })).trigger(orientationEvent);
50    }
51  });
52
53  //Add tiny class to header when you scroll down
54  $(window).scroll(function () {
55    if ($(document).scrollTop() == 0) {
56      $('.l-header').removeClass('tiny');
57    } else {
58      $('.l-header').addClass('tiny');
59    }
60  });
61
62
63  // Set equal column heights for certain elements. This is required so that we
64  // can align images vertically.
65  Drupal.behaviors.vrweb_foundation_equal_heights = {
66    attach: function(context, settings) {
67      var selectors = [
68          '.view-events.view-display-id-page'
69        ],
70        $selectors = $(selectors.join(','), context);
71
72      if ($selectors.length) {
73        $(window).on(orientationEvent, $.throttle(250, function() {
74          $selectors.find('article').each(function() {
75            $(this).find('> div.columns').removeAttr('height width').equalHeights();
76          });
77        })).trigger(orientationEvent);
78      }
79    }
80  };
81
82  // Make Update Favorites Cart button
83  Drupal.behaviors.favorites_update = {
84    attach: function(context, settings) {
85      $('.favorites-cart .block-vrweb-favorites-my-favorites-link .service-label').text("Update Cart");
86    }
87  }
88
89   Drupal.behaviors.foundationCollapseHack = {
90    attach: function (context, settings) {
91      // check whether we have a map
92      if (typeof Drupal.settings.gmap != 'undefined' && $('.view-display-id-block_location_by_nid').length) {
93        // on page load
94        $(window).load(function () {
95          // grab a map object
96          var $map = $('.view-display-id-block_location_by_nid');
97          // if we have a section container
98          if ($map.parents('.section-container').length > 0) {
99            // find any maps in these tabs and bind a click to it
100            $map.parents('section').find('p.title').children('a').click(function () {
101              // B.c of timing - it's important to wrap the resize stuff in a timeOut.
102              // This assures that getComputedStyle is not null when resize fires
103              var gmap = Drupal.gmap.getMap("gmap-auto1map-gmap0"),
104                lat = gmap.vars.latitude,
105                lng = gmap.vars.longitude,
106                zoom = gmap.vars.zoom;
107              setTimeout(function () {
108                google.maps.event.trigger(gmap.map, "resize");
109                gmap.map.setCenter(new google.maps.LatLng(lat, lng), zoom);
110              }, 0);
111            });
112          }
113        });
114      }
115    }
116  }
117  //Add class if location div exists as child of group
118  Drupal.behaviors.ttd_detect_banner_location = {
119    attach: function(context, settings) {
120      var selectors = [
121          '.node-event .group-header, .node-thing-to-do .group-header'
122        ],
123        $gh = $(selectors.join(','), context);
124      if($gh.children().hasClass("view-location-by-nid")) {
125      $gh.addClass("has-loc");
126      }
127    }
128  }
129  Drupal.behaviors.cookie_compliance_us = {
130    attach: function(context, settings) {
131      var endpoint = 'https://2a02y2kesb.execute-api.us-west-2.amazonaws.com/Production/IP2Country';
132      var cookieBanner = $('.cookie-compliance-banner-wrapper', context);
133      var apiKey = 'DEl93Q6Q4UEug3Gran8g8gNIglNVGGL2U5CvTqE5';
134      var COOKIE_ID = 'cookie_optin';
135
136      $.ajax({
137        url: endpoint,
138        type: 'POST',
139        headers: {
140          'X-Api-Key': apiKey,
141        },
142        success: function (response) {
143          if(response.country_code === 'US') {
144            $.cookie(COOKIE_ID, '1', { expires: 30 });
145            cookieBanner.remove();
146          }
147        }
148      });
149    }
150  }
151  Drupal.behaviors.reveal_messages = {
152    attach: function(context, settings) {
153      $('#status-messages.reveal-modal', context).foundation('reveal','open');
154    }
155  };
156  Drupal.behaviors.measure_vod = {
157    attach: function(context, settings) {
158      var vod = $('.block-views-b448c1a667acaa0227337f206f0c2fa5'); /* cache the selector */
159      $('.block-vrfusion-site-jhr-video-of-day').css({ height: vod.height() });
160    }
161  };
162
163  Drupal.behaviors.modernizr_tests = {
164    attach: function(context, settings) {
165
166      // Move user actions section to bottom on mobile
167      if(Modernizr.mq('only screen and (max-width: 767px)')) {
168
169        // Make accordions scroll to top on mobile
170        $(document).foundation('section', {
171          callback: function (){
172            var containerPos = $('.group-vr-full-property-info.section-container .active').offset().top;
173            $('html, body').animate({ scrollTop: containerPos }, 300);
174          }
175        });
176      }
177    }
178  }
179
180  // Fire off a resize event so Royalslider works when used in modals.
181  Drupal.behaviors.slider_resize = {
182    attach: function(context, settings) {
183      $('.reveal-royalslider').on('click', function () {
184        setTimeout(function() {
185          var slider = $('.field_gallery_images.reveal-modal .royalSlider').data('royalSlider');
186          slider.updateSliderSize(true);
187        }, 250);
188      })
189    }
190  }
191
192
193  Drupal.behaviors.equalize_package_teaser_heights = {
194    attach: function(context, settings) {
195      if (typeof $.fn.matchHeight != 'undefined') {
196        $('.node-special.node-teaser .group-content', context).matchHeight({byRow: true});
197      }
198    }
199  }
200
201  Drupal.behaviors.vrweb_foundation_toggle_search = {
202    attach: function(context,settings) {
203      var $search_toggle = $('.off-canvas-trigger a', context);
204      if (!$search_toggle.length) {
205        return;
206      }
207
208      $search_toggle.once('search-toggle', function() {
209        var $container = $('.page');
210
211        $search_toggle.toggle(function() {
212          $container.removeClass('hide-search').addClass('show-search');
213        }, function() {
214          $container.removeClass('show-search').addClass('hide-search');
215        });
216      });
217    }
218  }
219
220  Drupal.behaviors.vrweb_add_tm = {
221    attach: function (context, settings) {
222      var $callout = $('div.field-type-paragraphs > div', context);
223
224      $(document).ready(function () {
225        if ($('body').hasClass('front')) {
226          stripeTable();
227        }
228
229        var $title = $('.entity-paragraphs-item.odd div.field-name-field-title');
230
231        setTimeout(function() {
232          $title.html('Jackson Hole Vacation Rentals <span class="trade-mark">™</span>');
233        }, 500);
234      });
235
236      function stripeTable() {
237        var count = 1;
238        // get all visible table rows
239        $callout.each(function () {
240          // If table row is visible, strip accordingly.
241          // Row 0 (table headers) not striped.
242          if (this.rowIndex !== 0) {
243            if ((count % 2) != 0) {
244              // Remove class .even if applied previously
245              $(this).removeClass("even");
246              // Odd row, add class .odd
247              $(this).addClass("odd");
248              count++;
249            } else {
250              // Remove class .odd if applied previously
251              $(this).removeClass("odd");
252              // Even row, add class .even
253              $(this).addClass("even");
254              count++;
255            }
256          }
257        });
258      }
259    }
260  }
261
262  //Drupal.behaviors.vrweb_foundation_move_share = {
263  //  attach: function(context, settings) {
264  //    // Move share button below title.
265  //    if ($('body.search-results-page').length == 0) {
266  //      return;
267  //    }
268  //
269  //    $('#page-title').once('move-share-wrapper', function() {
270  //      $(this).after($('.bt-leads-share-url-form-wrapper').clone());
271  //    });
272  //  }
273  //}
274
275  Drupal.behaviors.vrweb_foundation_buy_special = {
276    attach: function(context, settings) {
277      $('.rc-pricing-special, .rc-pricing-ctb', context).once('rc-buy-pricing-submit', function() {
278        var $special = $(this);
279        $special.click(function() {
280          if ($(window).width() > 768) {
281            if ($special.hasClass('rc-pricing-special')) {
282              // If this is tablet or large, clicking on special pricing links takes you to checkout form.
283              $special.find('.rc-item-price-buy').submit();
284            }
285          }
286          else {
287            // Otherwise it opens the specials sidebar reveal modal.
288            $('.specials-sidebar-reveal-link').trigger('click');
289          }
290        });
291      });
292    }
293  }
294
295  Drupal.behaviors.sticky_sidebar = {
296    attach: function(context, settings) {
297      var $sidebar = $('.vrfusion-site-specials-sidebar-outer', context),
298        $sidebar_inner,
299        $window,
300        is_sticky,
301        left,
302        width,
303        height,
304        sidebar_height;
305
306      if (!$sidebar.length) {
307        return;
308      }
309
310      $sidebar_inner = $sidebar.find('.vrfusion-site-specials-sidebar');
311      if (!$sidebar_inner.length) {
312        return;
313      }
314
315      $sidebar.once('sticky-search', function() {
316        window.addEventListener('scroll', stickySearch, false);
317      });
318
319      $window = $(window);
320      height = $(window).height();
321      sidebar_height = $sidebar_inner.height();
322
323      function stickySearch() {
324        var r = $sidebar[0].getBoundingClientRect();
325        if (r.top < 0) {
326          if (!is_sticky) {
327            // If the user scrolled down below the specials sidebar, and it's not sticky yet, make it sticky.
328            $sidebar.addClass('sticky-enabled');
329            is_sticky = true;
330
331
332            // Set the inner sidebar width to match the outer sidebar wrapper.
333            $sidebar_inner.css({
334              left: r.left,
335              width: r.width,
336              maxHeight: height,
337              overflow: (sidebar_height > height) ? 'scroll-Y' : 'auto'
338            });
339          }
340        }
341        else if (is_sticky) {
342          // If the user has scrolled above the sidebar and it's still sticky, remove sticky class and fixed width.
343          $sidebar.removeClass('sticky-enabled');
344          is_sticky = false;
345          $sidebar_inner.css({
346            width: '100%',
347            maxHeight: 'none',
348            overflow: 'auto'
349          });
350        }
351      }
352
353      $(window).on(orientationEvent, $.throttle(250, function () {
354        var r, resize_height;
355        if (is_sticky) {
356          // If user resized browser and the sidebar is currently sticky, check to see if we need to resize the sidebar.
357          r = $sidebar[0].getBoundingClientRect();
358          resize_height = $window.height();
359          console.log(resize_height);
360          if (r.left != left || r.width != width || height != resize_height) {
361            // If the outer wrapper width or position has changed, update the inner sidebar position and width.
362            left = r.left;
363            width = r.width;
364            height = resize_height;
365            sidebar_height = $sidebar_inner.height();
366            $sidebar_inner.css({
367              left: left,
368              width: width,
369              maxHeight: height,
370              overflow: (sidebar_height > height) ? 'scroll-Y' : 'auto'
371            });
372          }
373        }
374      }));
375    }
376  };
377
378  /**
379   * Updates on wording when datepickers are changed
380   */
381  Drupal.behaviors.datepicker_messaging_updates = {
382    attach: function (context, settings) {
383
384      // Do not run this in the front page
385      if ($('body').is('.front')) {
386        return;
387      }
388
389      // Alter the behavior of each avail form found.
390      $(settings.rcItemAvailForm).each(function(ind, data) {
391        // Ensure a valid form is updated.
392        $('#' + data.id, context).once(function() {
393          // Get the main form and its date pickers.
394          let $wrapper = $(this);
395          let $datePickers = $('input.begin.hasDatepicker', $wrapper).add('input.end.hasDatepicker', $wrapper);
396
397          // Update the handlers run when dates are picked.
398          $datePickers.each(function() {
399            let $t = $(this);
400            let onSelect = $t.datepicker('option', 'onSelect');
401
402            // Store the current date set in datepicker, but with the correct option name
403            // as it's gonna be used as a previous thing, later.
404            $t.datepicker('option', {
405              'previousDate': $t.datepicker("getDate")?.toLocaleDateString("en-US"),
406            });
407
408            // Custom onSelect handlers used to trigger all changes.
409            let customOnSelect = function(e) {
410              // Call the normal handler set, if any.
411              if (typeof onSelect === 'function') {
412                onSelect(e);
413              }
414
415              // Update the date format used in passed argument.
416              e = new Date(e);
417              e = e.toLocaleDateString("en-US");
418
419              // Get the previous date set.
420              let previousDate = $t.datepicker('option', 'previousDate');
421
422              // Store the date in the helper option.
423              $t.datepicker('option', {
424                'previousDate': $t.datepicker("getDate").toLocaleDateString("en-US"),
425              });
426
427              // In case there is no previous date, nothing left to do.
428              if (!previousDate) {
429                return;
430              }
431
432              // In case current date and previous date are the same, nothing left to do.
433              if (previousDate == e) {
434                return;
435              }
436
437              // Update the form's submit button.
438              let submit = $t.closest('form.rc-riot-avail-filter-form').find('input:submit');
439              if (!submit.length) {
440                return;
441              }
442
443              // Update the button text after a visual effect.
444              options = {};
445              submit.parent().effect("bounce", options, 100, function() {
446                submit.val(Drupal.t("Update Availability"));
447              });
448            }
449
450            // Update the datepicker with custom handlers.
451            $t.datepicker('option', {
452              onSelect: customOnSelect,
453            });
454          });
455        });
456      });
457
458    }
459  };
460
461  /**
462   * Updates sorting option in searches when on occupancy filter data is coming. But only once.
463   */
464     Drupal.behaviors.update_sorting_search = {
465      attach: function (context, settings) {
466
467        if(typeof RiotTagsDispatch !== 'undefined') {
468          // Wait until a search is dispatched.
469          RiotTagsDispatch.on('RiotSolrItemsUpdated', function(e) {
470            // Ensure the checking only happens once.
471            $('body').once('occupancy-filter', function() {
472              // Verify the occupancy filter was used.
473              let hash = decodeURIComponent(window.location.hash);
474
475              // No occupancy filter used, nothing left to do.
476              if (!hash.includes('$occ_total')) {
477                return;
478              }
479
480              // Build the option that's desired to be selected.
481              let option = {
482                "field": "fs_rc_core_lodging_product$beds",
483                "handler": "sortNumeric",
484                "label": "Beds - low to high",
485                "direction": false
486              }
487              option = btoa(JSON.stringify(option));
488
489              // Locate the solr sort select and select the new option.
490              // Use a timeout function to ensure the process is moved out of the normal flow and run last.
491              setTimeout(function() {
492                $('riot-solr-sorts select.rs-sorts').val(option);
493                $('riot-solr-sorts select.rs-sorts').get(0).dispatchEvent(new Event('change'));
494              }, 0);
495            });
496          });
497        }
498      }
499    };
500
501  // Drupal.behaviors.vrweb_foundation_ti_options = {
502  //   attach: function(context, settings) {
503  //     console.log('ok');
504  //     $('tr:contains(\'Insurance\') input').click(function() {
505  //       $('tr:contains(\'Insurance\') input').not(this).prop('checked', false);
506  //       $('tr:contains(\'Insurance\') input').not(this).prop('disabled', true);
507  //       console.log('hello');
508  //     });
509  //   }
510  // }
511
512  Drupal.behaviors.jhr_insurance = {
513    attach: function(context, settings) {
514      var $table = $('.jhr-insurance-options', context),
515          $charges,
516          $decline;
517
518      if ($table.length == 0) {
519        return;
520      }
521
522      $charges = $table.find('input');
523      $decline = $table.find('.form-item-charges-decline-insurance').find('input');
524
525      $charges.click(function() {
526        var $selected = $(this);
527        if ($selected.val() == 1 && $selected.attr('name') != $decline.attr('name')) {
528          // User selected an insurance, so deselect the 'Decline Insurance' radio.
529          $decline.prop('checked', false);
530        }
531
532        $charges.each(function () {
533          var $radio = $(this);
534          if ($radio.attr('name') != $selected.attr('name') && $radio.val() == -1) {
535            // Decline all insurance options other than the one selected.
536            $radio.prop('checked', true);
537          }
538        });
539      });
540
541      $decline.click(function() {
542        if ($(this).prop('checked')) {
543          // If user clicks 'Decline Insurance', decline each insurance option.
544          $charges.each(function () {
545            var $radio = $(this);
546            if ($radio.val() == -1) {
547              $radio.prop('checked', true);
548            }
549          });
550        }
551      });
552    }
553  };
554
555  Drupal.behaviors.checkout = {
556    attach: function (context, settings) {
557
558      $('.line-item-fees-toggle', context).once('rcjsLineItemFees', function () {
559        $(this).click(function () {
560          var desc = $('tr.grouped-items', context);
561          if ($(desc).is(':visible')) {
562            $(desc).hide(150);
563            $(this).text($(this).attr('data-show-copy'));
564          } else {
565            $(desc).show(150);
566            $(this).text($(this).attr('data-hide-copy'));
567          }
568        });
569      });
570    }
571  };
572  
573  Drupal.behaviors.remove_hotjar = {
574    attach: function (context, settings) {
575       $(window).load(function() {
576         setTimeout(function() {
577          let hotjar = document.querySelector("script[src='https://static.hotjar.com/c/hotjar-3838894.js?sv=7']", context);
578          let hotjarModules = document.querySelector("script[src='https://script.hotjar.com/modules.6c69b5997f314810cfe8.js']", context);
579          
580          if(hotjar != null) {
581            hotjar.parentNode.removeChild(hotjar);
582          }
583          
584          if(hotjarModules != null) {
585            hotjarModules.parentNode.removeChild(hotjarModules);
586          }
587         }, 4000);
588       })
589    }
590  };
591
592  //Sort quick search results by exact date first, then by flexible arrivals
593  if (typeof RiotSolrItemSortHandlers !== 'undefined') {
594    var RCRiotAvailPricing = riot.mixin('RCRiotAvailPricing');
595    RiotSolrItemSortHandlers.sortRandom.primer = function (is_eid) {
596      var lastQuery = RCRiotAvailPricing.getLastSearchQuery();
597      var pricing = RCRiotAvailPricing.getItemPricing(is_eid);
598      if (pricing)
599      {
600        // Check if dates are match or it they are flexible
601        // If flexible send to back
602        if (pricing.prices[0].bt != RCRiotAvailPricing.parseDate(lastQuery.rcav.begin) || pricing.prices[0].et != RCRiotAvailPricing.parseDate(lastQuery.rcav.end)) {
603          return 9999;
604        }
605      }
606
607      var max = 9999,
608        min = 1;
609      return Math.floor(Math.random() * (max - min)) + min;
610    }
611
612    RiotSolrItemSortHandlers.sortRandom.callback = function (items, field, reverse) {
613      field = 'is_eid';
614      var self = this,
615        r = !reverse ? 1 : -1;
616      items.sort(function (a, b) {
617        return (a = self.primer(a[field])), (b = self.primer(b[field])), r * ((a > b) - (b > a));
618      });
619      return items;
620    }
621  };
622
623  // Add additional classes and messaging for minimum stays.
624  Drupal.behaviors.datepicker_overrides = {
625    attach: function (context, settings) {
626      $(settings.rcItemAvailForm).each(function (ind, data) {
627        $('#' + data.id, context).once(function () {
628          var $wrapper = $(this);
629          var $begin = $('input.begin.hasDatepicker', $wrapper);
630
631          $('input.hasDatepicker', $wrapper).each(function () {
632            $(this).on('change', clearDate);
633          });
634
635          function clearDate() {
636            var $t = $(this);
637            $t.removeClass('hasDates').parent().removeClass('has-dates').find('a.clearDate').remove().end();
638            $t.addClass('hasDates').parent().addClass('has-dates');
639            $( "<a>", {
640              text: "Clear",
641              click: function() {
642                $t.datepicker( "setDate" , null );
643                $t.removeClass('hasDates').parent().removeClass('has-dates');
644                $(this).remove();
645                return false;
646              },
647              class: 'clearDate'
648            }).appendTo($(this).parent());
649          }
650
651          if (!data.hasOwnProperty('eid')) {
652            // Only apply on detail page calendars.
653            return;
654          }
655
656          function customGetMinDate(tm) {
657            // Get minimum stay from global and property restrictions for a specific date.
658            var global_min = data.mns,
659              local_min = 1;
660            if (data.restr) {
661              for (var r in data.restr) {
662                if (data.restr[r].bdt <= tm && data.restr[r].edt >= tm) {
663                  if (data.restr[r].mn > 0) {
664                    local_min = data.restr[r].mn;
665                  }
666                  found = true;
667                  break;
668                }
669              }
670            }
671
672            return global_min > local_min ? global_min : local_min;
673          }
674
675          $('input.end.hasDatepicker', $wrapper).each(function () {
676            var $t = $(this),
677              beforeShow = $t.datepicker('option', 'beforeShow'),
678              beforeShowDay = $t.datepicker('option', 'beforeShowDay'),
679              customBeforeShow = function (input) {
680                // Add beforeShow handler to insert departure date message on departure datepicker.
681                var avail = [],
682                  $datepicker,
683                  begin,
684                  min_days;
685
686                if (beforeShow) {
687                  // Determine availability by calling default beforeShow handler.
688                  avail = beforeShow(input);
689
690                  if (typeof avail.minDate != 'undefined') {
691                    // If we found a minimum stay for the selected begin date, add minimum stay messaging.
692                    $datepicker = $("#ui-datepicker-div");
693                    begin = $begin.datepicker("getDate");
694                    min_days = customGetMinDate(begin.getTime());
695                    if (min_days > 1) {
696                      setTimeout(function () {
697                        var year = new Intl.DateTimeFormat('en', { year: 'numeric' }).format(begin),
698                          month = new Intl.DateTimeFormat('en', { month: 'short' }).format(begin),
699                          day = new Intl.DateTimeFormat('en', { day: 'numeric' }).format(begin),
700                          date = month + ' ' + day,
701                          msg = 'Minimum stay for arrival on ' + date + ' is ' + min_days + ' nights.',
702                          html = '<tr class="vrw-last-row"><td class="vrw-next-departure" colspan="7">' + msg + '</td></tr>';
703
704                        // Add extra row to calendar for minimum stay message.
705                        $datepicker.find('tr:last').after(html);
706                      }, 0);
707                    }
708                  }
709                  return avail;
710                }
711              },
712
713              customBeforeShowDay = function (date) {
714                // Add custom beforeShowDay to add a class marking dates restricted by minimum stay restrictions.
715                var begin = $begin.datepicker("getDate"),
716                  c = beforeShowDay(date),
717                  time = date.getTime(),
718                  begin_time,
719                  min_days,
720                  min_date;
721
722                if (begin) {
723                  begin_time = begin.getTime();
724                  min_days = customGetMinDate(begin_time);
725                  min_date = new Date(begin_time);
726                  min_date.setDate(min_date.getDate() + min_days);
727                  if (time > begin_time && time < min_date.getTime()) {
728                    // Add minimum stay class to dates within minimum day restrictions.
729                    c[1] += ' av-min-stay';
730                  }
731                }
732                return c;
733              };
734
735            $t.datepicker('option', {
736              beforeShow: customBeforeShow,
737              beforeShowDay: customBeforeShowDay
738            });
739          });
740        });
741      });
742    }
743  };
744
745  Drupal.behaviors.responsive_rs = {
746    attach: function(context, settings) {
747      if (typeof settings.bt_virtual_tours == 'undefined' ||
748        typeof settings.bt_virtual_tours.options.visibleNearby == 'undefined' ||
749        !settings.bt_virtual_tours.options.bt.responsiveRS ||
750        !settings.bt_virtual_tours.options.visibleNearby.enabled ||
751        !settings.bt_virtual_tours.options.visibleNearby.centerArea) {
752        return;
753      }
754
755      var options = settings.bt_virtual_tours.options,
756        visible_nearby = options.visibleNearby.centerArea,
757        height_limit = (options.bt.max_height == 'undefined') ? 0 : options.bt.max_height,
758        spacing = options.slidesSpacing,
759        breakpoint = (options.bt.breakpoint == 'undefined') ? 0 : options.bt.breakpoint,
760        breakpoint_center_area = (options.bt.breakpointCenterArea == 'undefined') ? 0 : options.bt.breakpointCenterArea,
761        aspect = (typeof settings.vrw == 'undefined' || typeof settings.vrw.rs_aspect == 'undefined') ? options.autoScaleSliderWidth / options.autoScaleSliderHeight : settings.vrw.rs_aspect,
762        $rs = $('.rc-core-item-api-images-royalslider', context),
763        slider,
764        $thumbs;
765
766      if (!$rs.length) {
767        return;
768      }
769
770      slider = $rs.data('royalSlider');
771      $thumbs = $rs.find('.rsThumbs');
772
773      slider.ev.on('rsEnterFullscreen', function () {
774        slider.width = 0;
775        slider.st.visibleNearby.centerArea = 1;
776        slider.updateSliderSize(true);
777      });
778
779      slider.ev.on('rsExitFullscreen', function () {
780        resize_slider();
781      });
782
783      $(window).on(orientationEvent, jQuery.throttle(100, function () {
784        resize_slider();
785      }));
786
787      function resize_slider() {
788        var thumbs_height = $thumbs.height(),
789          max_height = height_limit - thumbs_height - (spacing * 2),
790          max_width = (max_height * aspect) + (spacing * 2),
791          slider_width,
792          width,
793          height,
794          center_area = visible_nearby,
795          window_width = $(window).width();
796
797        if (slider.isFullscreen) {
798          return;
799        }
800
801        if (breakpoint && breakpoint_center_area && window_width < breakpoint) {
802          center_area = breakpoint_center_area;
803        }
804
805        slider_width = document.documentElement.clientWidth;
806        width = slider_width * center_area;
807        if (spacing && center_area < 1) {
808          width -= spacing;
809        }
810        height = (width / aspect) + spacing + thumbs_height;
811        if (breakpoint && height_limit && window_width >= breakpoint && height > height_limit) {
812          height = height_limit;
813          center_area = max_width / slider_width;
814        }
815
816        if (window_width < 768) {
817          slider.st.sliderDrag = true;
818        }
819        else {
820          slider.st.sliderDrag = false;
821        }
822
823        slider.width = 0;
824        slider.st.visibleNearby.centerArea = center_area;
825        slider.st.autoScaleSliderWidth = slider_width;
826        slider.st.autoScaleSliderHeight = height;
827        slider.updateSliderSize(true);
828      }
829    }
830  }
831
832  Drupal.behaviors.toggle_desc = {
833    attach: function (context, settings) {
834      $('.toggle-desc', context).click(function () {
835        var $this = $(this),
836          text = '',
837          $wrapper = $(this).siblings('.body-wrapper');
838
839        if ($this.hasClass('toggle-open')) {
840          $wrapper.animate({
841            height: 220,
842          }, 100);
843          $('html').animate({
844            scrollTop: $wrapper.offset().top,
845          }, 100);
846
847          $wrapper.removeClass('wrapper-open');
848          $this.removeClass('toggle-open');
849        }
850        else {
851          $wrapper.animate({
852            height: $wrapper.children().height(),
853          }, 500);
854          $wrapper.addClass('wrapper-open');
855          $this.addClass('toggle-open');
856        }
857
858        text = $this.html();
859        $this.html($this.data('alt-text'));
860        $this.data('alt-text', text);
861
862        return false;
863      });
864    }
865  };
866
867  Drupal.behaviors.move_checkout_dates = {
868    attach: function (context, settings) {
869      var selectors = [
870        'body.checkout-page .wrapper-dates-price'
871      ];
872      var $summary = $(selectors.join(','), context);
873      $location = $('body.checkout-page .node-vr-listing.view-mode-vrcheckout .group-right', context);
874
875      $summary.appendTo($location);
876    }
877  };
878  
879  Drupal.behaviors.add_preferences_link = {
880    attach: function (context, settings) {
881      var selectors = $('body.checkout-page', context);
882      
883      if(selectors.length) {
884        selectors.append('<div class="footer-copyright" style="text-align:center; margin-bottom:2em;"><a href="#manage_cookies">Update Preferences</a></div>');
885      }
886    }
887  };
888
889  Drupal.behaviors.vrweb_searches_treatments = {
890    attach: function (context, settings) {
891
892      // Create mutation objects just once.
893      $('body').once(function () {
894        // Update labels from every option set for Flexible Search.
895        new MutationObserver(function (mutations) {
896          // Update the Bedrooms slider value, for Studio.
897          let slider_min = $('riot-solr-range-slider[data-facetid="RiotSolrFacetRanges-fs_rc_core_lodging_product$beds"] div.noUi-tooltip:first');
898          let slider_max = $('riot-solr-range-slider[data-facetid="RiotSolrFacetRanges-fs_rc_core_lodging_product$beds"] div.noUi-tooltip:last');
899          let min = null;
900          if (slider_min.length) {
901            min = slider_min.html();
902          }
903
904          let max = null;
905          if (slider_max.length) {
906            max = slider_max.html();
907          }
908
909          if (min == '0') {
910            slider_min.html("Studio");
911          }
912
913          if (max == '0') {
914            slider_max.html("");
915          }
916
917          // If bedrooms is exact match search, replace 'to ...' text.
918          let current_slider_min = $('riot-solr-container >
918 riot-solr-current-search [data-facet*="fs_rc_core_lodging_product$beds"]')
919          if (current_slider_min.length && min == max) {
920            let min_text = current_slider_min.html();
921            let pos = min_text.indexOf(' to ' + max);
922            if (pos != -1) {
923              new_min = min_text.replace(' to ' + max, '');
924              if (new_min != min_text) {
925                current_slider_min.html(new_min);
926              }
927            }
928          }
929
930          // Update the Bedrooms slider current search value, for Studio.
931          if (current_slider_min.length && current_slider_min.html().match(/\:\s*0/)) {
932            let new_min = current_slider_min.html().replace(/\:\s*0/, ': Studio');
933            current_slider_min.html(new_min);
934          }
935        }).observe(
936          document.querySelector('body'),
937          {
938            subtree: true,
939            childList: true,
940            characterData: true,
941          }
942        );
943      });
944    }
945  }
946
947})(jQuery, Drupal);

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.