PageSourceSearch

https://www.brocketarms.com/bundles/eviivo/availabilityDefaultSear…CtLH7c8xBqaMSMQhyWy6iC7dsqyu3e7n7UuzFNmVBs1

js brocketarms.com collected 2026-10-04 22:16:16 UTC 25,173 bytes, 611 lines download raw bytes

1window.eviivo = window.eviivo ? window.eviivo : {};
2window.eviivo.availabilitySearch = window.eviivo.availabilitySearch ? window.eviivo.availabilitySearch : {};
3
4window.eviivo.availabilitySearch = function ($) {
5
6    var defaultOptions = {
7        isDefaultReferrer: true,
8        defaultNightsServiced: 0,
9        roomsLimit: 3,   //default room limit is 3 if not overriden by external settings
10        eviivoSearchBoxId: "#eviivo-availability-search",   //default serach box id is "eviivo-availability-search" if not overriden by external settings
11        cultureLanguageCode: "en-GB",
12        baseSearchUrl: "",
13        resources: {
14            adults: "Adults",
15            children: "Children",
16            rooms: "Room(s)",
17            room: "Room"
18        },
19        //have this search criteria as a default for easier way to parse the query string and easier way to customize the search if properties want to
20        criteria:
21        {
22            startDate: null,
23            endDate: null,
24            occupancy: [{ adults: 2, children: 0 }]
25        }
26    };
27    var options;
28    var occupancySelectionHtmlClone;
29    var roomsRow;
30    var currentDate;
31    var simpleVersion;
32
33    var $tooltip;
34    var $addButton;
35    var $removeButton;
36    var $searchButton;
37    var $startDate;
38    var $endDate;
39    var $doneButton;
40    var $occupancySelectors;
41    var $firstAdultsOccupancy;
42    var $showPricesButtons;
43    var $searchBar;
44    var $datePicker;
45    var $viewportWidth;
46    var $safariBrowser;
47    var $isChannelSearch;
48    var querystringHelper;
49    var $formFieldSet;
50    var $datePickerSelectionToolTip;
51    var $infoTooltip;
52
53    ///<summary>extend Date javascript object and add extra function "addHours"</summary>
54    Date.prototype.addHours = function (hours) {
55        this.setHours(this.getHours() + hours);
56        return this;
57    };
58
59    ///<summary>Main init method of the eviivo.availabilitySearch object</summary>
60    ///<param name="settings">external settings</param>
61    function init(settings) {
62        //extend internal settings with external ones
63        options = $.extend(defaultOptions, settings);
64
65        //cache jquerySelectors either as jQuery objects or just as simple text selectors
66        occupancySelectionHtmlClone = $(options.eviivoSearchBoxId + " div.column-outer").html();
67        roomsRow = options.eviivoSearchBoxId + " div.column-inner";
68
69        //cache jquery objects
70        $tooltip = $(options.eviivoSearchBoxId + " div.cp-tooltip");
71        $addButton = $(options.eviivoSearchBoxId + " #btn-addRoom");
72        $removeButton = $(options.eviivoSearchBoxId + " #btn-removeRoom");
73        $searchButton = $(options.eviivoSearchBoxId + " button.cp-button-price");
74        $showPricesButtons = $("#mod-results div.results-price button.cp-button-showprices");
75        $startDate = $(options.eviivoSearchBoxId + " input#eviivo-start-date");
76        $endDate = $(options.eviivoSearchBoxId + " input#eviivo-end-date");
77        $doneButton = $(options.eviivoSearchBoxId + " .actions button");
78        $firstAdultsOccupancy = $(options.eviivoSearchBoxId + " div.column-inner:first-child span.column-adult span.ui-selectmenu-button");
79        $searchBar = $("#eviivo-availability-search");
80        $datePicker = $("#ui-datepicker-div");
81        $isChannelSearch = $("#submit-reservation #cbe");
82        $formFieldSet = $('.column-outer');
83        $viewportWidth = $(window).width();
84        //use this array to cache the occupancy selector menus for easier manipulation
85        $occupancySelectors = [];
86        $safariBrowser = false;
87        $datePickerSelectionToolTip = $('#datepicker-tooltip');
88        $infoTooltip = $(".cp-tooltip-info");
89        querystringHelper = eviivo.utils.queryStringHelper;
90        if (typeof querystringHelper === "undefined") {
91            console.log("eviivo.utils.queryStringHelper was not loaded therefore this page might not work properly");
92        }
93
94        //init datepicker (set culture and min date - not in the past)
95        var minDate = new Date();
96        if (options.defaultNightsServiced == null || options.isDefaultReferrer === false) {
97            options.defaultNightsServiced = 0;
98        }
99        minDate.setDate(minDate.getDate() + options.defaultNightsServiced);
100
101        var dtFormat = eviivo.webcore.formatting.datetime.evGetDateDisplayFormat(options.cultureLanguageCode, "medium");
102
103        //setup culture and get users current culture
104        var culture = "en-gb";
105        if (options.selectedCultureLanguageCode != null) {
106            culture = options.selectedCultureLanguageCode;
107        }
108        
109        //Date has been extended via eviivo.webcore.formatting.js, this function takes the current users culture as a parameter and then determines what first day of the week should be, returning it as an offset used with date pickers
110        var d = new Date();
111        var firstDayOffset = d.evStandardFirstDayCalendarOffset(culture);
112
113        $.datepicker.setDefaults(
114            $.extend(
115            {
116                'dateFormat': dtFormat,
117                'altFormat': dtFormat,
118                'showOtherMonths': true,
119                'selectOtherMonths': true,
120                'minDate': minDate,
121                'firstDay': firstDayOffset
122            }
123            )
124        );
125
126        $startDate.datepicker({
127            onSelect: startDateSelectHandler
128        });
129
130        $endDate.datepicker({
131            onSelect: endDateSelectHandler
132        });
133
134        //init end datepicker with culture specifics, min date as current date and onSelect custom handler
135        $endDate.datepicker();
136
137        //attach click handler for add room button
138        $addButton.on("click", addRoomClickHandler);
139        //attach click handler for remove room button
140        $removeButton.on("click", removeRoomClickHandler);
141        $datePickerSelectionToolTip.on("click", clearDatePickerTooltip);
142        //attach click handler for hiding the occupancy tooltip (to "done" button and to DOM document)
143        $doneButton.on("click", tooltipHide).on("blur", tooltipHide);
144        $(document).on('keydown', tooltipHideEscape);
145
146        //attach click handler for showing the occupancy tooltip
147        $(options.eviivoSearchBoxId + " .icon-guest").on("click", tooltipShow);
148        $(options.eviivoSearchBoxId + " .icon-guest a").on("click", tooltipShow);
149
150        //initialize the first row of occupancy selectors in the occupancy tooltip
151        initSelectMenu($(options.eviivoSearchBoxId + " div.column-inner:first-child select.cp-select"));
152
153        //handle the click outside the occupancy tooltip (close the tooltip and focus on the search price button)
154        $(document).on("click", tooltipOutsideClick);
155
156        //action for search button
157        $searchButton.on("click", triggerSearch);
158
159        //action for show prices button
160        $showPricesButtons.on("click", showStartDateCalendar);
161
162        //first try to extract search criteria from query string
163        extractCriteria();
164        //init search criteria (either from extracted query string keys or from default values)
165        initSearchForm();
166
167        $infoTooltip.on("click", hideInfoToolTip);
168
169
170        validate(true);
171
172
173    }
174
175
176    ///<summary>Initialize occupancy selectors in the occupancy tooltip</summary>
177    ///<param name="selector">the dropdown jquery selector</param>
178    function initSelectMenu(selector) {
179        var selectors = selector.selectmenu({
180            change: highlightOccupancy
181        });
182
183        $occupancySelectors.push({ adults: selectors[0], children: selectors[1] });
184    }
185
186    ///<summary>Occupancy selector onChange handler</summary>
187    function occupancySelectHandler() {
188        var totalAdults = 0;
189        $(options.eviivoSearchBoxId + " div.column-inner span.column-adult .ui-selectmenu-text").each(function (i, e) {
190            totalAdults += extractNumber($(e));
191        });
192
193        var totalChildren = 0;
194        $(options.eviivoSearchBoxId + " div.column-inner span.column-child .ui-selectmenu-text").each(function (i, e) {
195            totalChildren += extractNumber($(e));
196        });
197
198        var numberOfRooms = $(roomsRow).length;
199        var searchBoxText = $(options.eviivoSearchBoxId + " .cp-inputValues a span");
200        var roomText = "";
201        if (numberOfRooms > 1) {
202            roomText = options.resources.rooms;
203        } else {
204            roomText = options.resources.room;
205        }
206        searchBoxText.html(totalAdults + " " + options.resources.adults + " " + totalChildren + " " + options.resources.children + " " + numberOfRooms + " " + roomText);
207    }
208
209    ///<summary>highlight the occupancy text when switching values</summary>
210    function highlightOccupancy() {
211        occupancySelectHandler();
212        var searchBoxText = $(options.eviivoSearchBoxId + " .cp-inputValues a");
213        searchBoxText.fadeIn("slow", function () {
214            searchBoxText.css("color", "#000");
215        });
216    }
217
218    ///<summary>Give each room added a number</summary>
219    function numberRoomTitle() {
220        var count = 1;
221        $(".column-outer .column-inner").each(function () {
222            var countTitle = options.resources.room + " " + count;
223
224            $(this).find(".room").html(countTitle);
225
226            count++;
227        });
228    }
229
230    //<summary>Change number of rooms selected in helper text</summary>
231    function numberRoomHelper() {
232        var roomTotal = $(".column-outer .column-inner").length;
233        var roomRow = $(".room-counter");
234        var resource;
235        if (roomTotal > 1) {
236            resource = options.resources.roomsAdded;
237        } else {
238            resource = options.resources.roomAdded;
239        }
240        var roomHtml = resource.replace(new RegExp('\\{' + 0 + '\\}', 'gm'), roomTotal);
241        roomRow.html(roomHtml);
242        roomRow.addClass('pulse');
243
244        var newRow = roomRow.clone(true);
245        roomRow.before(newRow);
246        $(".room-counter:last").remove();
247    }
248
249    ///<summary>Add room onClick handler</summary>
250    function addRoomClickHandler() {
251        var numberOfRooms = $(roomsRow).length;
252        if (numberOfRooms < options.roomsLimit) {
253            $(options.eviivoSearchBoxId + " div.column-outer").append(occupancySelectionHtmlClone).addClass("cloned");
254            initSelectMenu($(options.eviivoSearchBoxId + " div.column-inner:last-child select.cp-select"));
255            occupancySelectHandler();
256            numberRoomTitle();
257            numberRoomHelper();
258        }
259        setTooltipButtonsStatus();
260    }
261
262    ///<summary>Remove room onClick handler</summary>
263    function removeRoomClickHandler() {
264        var numberOfRooms = $(roomsRow).length;
265        if (numberOfRooms > 1) {
266            $(options.eviivoSearchBoxId + " div.column-inner:last").remove();
267            occupancySelectHandler();
268            numberRoomHelper();
269        }
270        setTooltipButtonsStatus();
271    }
272
273    ///<summary>Set the disabled status of the add and remove room buttons in the occupancy tooltip</summary>
274    function setTooltipButtonsStatus() {
275        var numberOfRooms = $(roomsRow).length;
276        if (numberOfRooms > 1) {
277            $removeButton.removeAttr("disabled");
278        } else {
279            $removeButton.attr("disabled", "disabled");
280            //once disabled the "remove button" we focus on the "add button" for better interaction
281            $addButton.focus();
282        }
283        if (numberOfRooms < options.roomsLimit) {
284            $addButton.removeAttr("disabled");
285        } else {
286            $addButton.attr("disabled", "disabled");
287            //once disabled the "add button" we focus on the "remove button" for better interaction
288            $removeButton.focus();
289        }
290        $(options.eviivoSearchBoxId + " div.column-outer").removeClass("overflow");
291        if (numberOfRooms > 2) {
292            $(options.eviivoSearchBoxId + " div.column-outer").addClass("overflow");
293        }
294    }
295
296    ///<summary>Hide tooltip when clicking outside the tooltip area</summary>
297    function tooltipOutsideClick(e) {
298        if (!$(e.target).hasClass("ui-menu-item-wrapper") && !$(e.target).hasClass("ui-menu-item") && !$(e.target).hasClass("cp-tooltip") && $(e.target).parents("div.cp-tooltip").length === 0) {
299            tooltipHide(e, true);
300        }
301    }
302
303    ///<summary>Hide tooltip handler on escape key</summary>
304    function tooltipHideEscape(e) {
305        if (e.keyCode === 27) {
306            tooltipHide(e, true);
307        }
308    }
309
310    ///<summary>Hide tooltip handler</summary>
311    function tooltipHide(e, bypassFocus) {
312        if ($tooltip.is(":visible")) {
313            $tooltip.hide();
314
315            //we check if we bypass focus for search button
316            if (!bypassFocus) {
317                $searchButton.focus();
318            }
319        }
320    }
321
322    ///<summary>Show tooltip handler</summary>
323    function tooltipShow(e) {
324        if (e !== null) {
325            e.stopPropagation();
326        }
327        if (($tooltip).is(":hidden")) {
328            $tooltip.show('fast');
329            //when showing tooltip we focus on first select input element
330            $firstAdultsOccupancy.focus();
331        }
332    }
333
334    function hideInfoToolTip() {
335        //hide info tooltip if visible
336        if ($infoTooltip.is(":visible")) {
337            $infoTooltip.hide();
338        }
339    }
340
341    ///<summary>Performs a validation on all the fields necessary to make the autocomplete / location result valid</summary>
342    function validate(isOnLoadValidation) {
343        // if both dates fields are empty
344        if ($startDate.val() === "" && $endDate.val() === "") {
345            if (isOnLoadValidation) {
346                $datePickerSelectionToolTip.addClass("infotip");
347            } else {
348                $startDate.addClass("invalid");
349                $endDate.addClass("invalid");
350            }
351            $datePickerSelectionToolTip.show();
352            return false;
353        }
354        // if start date field is empty
355        if ($startDate.val() === "") {
356            if (isOnLoadValidation) {
357                $datePickerSelectionToolTip.addClass("infotip");
358            } else {
359                $startDate.addClass("invalid");
360            }
361            $datePickerSelectionToolTip.show();
362            return false;
363        }
364        // if end date field is empty
365        if ($endDate.val() === "") {
366            if (isOnLoadValidation) {
367                $datePickerSelectionToolTip.addClass("infotip");
368            } else {
369                $endDate.addClass("invalid");
370            }
371            $datePickerSelectionToolTip.show();
372            return false;
373        }
374        clearDatePickerTooltip();
375        return true;
376
377    }
378
379
380    function clearDatePickerTooltip() {
381        $startDate.removeClass("invalid");
382        $endDate.removeClass("invalid");
383        $datePickerSelectionToolTip.removeClass("infotip");
384        $datePickerSelectionToolTip.hide();
385    }
386
387
388    ///<summary>Extract search criteria from querystring and populate search form</summary>
389    function extractCriteria() {
390        var criteria = options.criteria;
391        var src = window.location.href;
392        var isRoomCount = false;
393
394        //extract all query string keys by using reg exp
395        var qsJson = querystringHelper.getAllKeys(src);
396
397        //set start and end dates
398        if (qsJson["startdate"] !== null) {
399            criteria.startDate = new Date(qsJson["startdate"]);
400        }
401        if (qsJson["enddate"] !== null) {
402            criteria.endDate = new Date(qsJson["enddate"]);
403        }
404
405        //in case we had number of nights from legacy URL formats
406        if (qsJson["nights"] !== null) {
407            var nights = parseInt(qsJson["nights"]);
408            //in case we had number of nights from legacy URL formats
409            if (!isNaN(nights)) {
410                //we have to re-construct the date object due to fact it will change the original is we only assign
411                criteria.endDate = new Date(criteria.startDate.getFullYear(), criteria.startDate.getMonth(), criteria.startDate.getDate(), 0, 0, 0);
412                criteria.endDate.addHours(24 * nights);
413            }
414        }
415
416        //make sure to persist the display format
417        if (qsJson["simpleversion"] !== null) {
418            simpleVersion = qsJson["simpleversion"];
419        }
420
421        if (qsJson["noofrooms"] !== null) {
422            isRoomCount = qsJson["noofrooms"] >= 0;
423        }
424
425        criteria.occupancy = [];
426
427        //pass through all query string keys and construct the occupancy selectors
428        $.each(qsJson, function (key, value) {
429            //check for existance of adults and/or children params
430            var isAdults = key.indexOf("adults") >= 0;
431            var isChildren = key.indexOf("children") >= 0;
432
433            if (isAdults || isChildren > 0) {
434                //check to see which is the occupancy group the query string key refers to
435                var occupancyRegEx = new RegExp("[a-zA-Z]+([0-9]+)");
436                // extract the "index" of the adults or children (eg. adults1) - we need to consider them as being 0 base even though they come as 1 based in the URL
437                var index = parseInt(occupancyRegEx.exec(key)[1]) - 1;
438
439                // if room count is used exit loop if the "index" of the adults or children is greater than the noofrooms query string value
440                if (isRoomCount && (index + 1) > parseInt(qsJson["noofrooms"]))
441                    return false;
442
443                //construct extra occupancy groups (in case it's needed)
444                while (index > options.criteria.occupancy.length - 1) {
445                    criteria.occupancy.push({ adults: 0, children: 0 });
446                }
447
448                //based on key, set the appropriate field for occupancy
449                if (isAdults) {
450                    criteria.occupancy[index].adults = value;
451
452                } else if (isChildren) {
453                    criteria.occupancy[index].children = value;
454                }
455            }
456        });
457
458        return criteria;
459    }
460
461    ///<summary>Construct the search URL base on the base URL and the selected parameters</summary>
462    function triggerSearch() {
463
464        if (!validate()) {
465            return;
466        }
467
468        var searchUrl = options.baseSearchUrl;
469        var src = window.location.href;
470        var originalQueryString = querystringHelper.getAllKeys(src);
471        var queryStrings = jQuery.extend({}, originalQueryString);
472
473        var startDate = $startDate.datepicker("getDate");
474        var endDate = $endDate.datepicker("getDate");
475
476        if (startDate !== null) {
477            querystringHelper.addKey(queryStrings, "startdate", startDate.evStandardIso8601DateExtended());
478        }
479        if (endDate !== null) {
480            querystringHelper.addKey(queryStrings, "enddate", endDate.evStandardIso8601DateExtended());
481        }
482
483        querystringHelper.deleteKeyWithRegex(queryStrings, "adults");
484        querystringHelper.deleteKeyWithRegex(queryStrings, "children");
485        querystringHelper.deleteKeyWithRegex(queryStrings, "noofrooms");
486        $(options.eviivoSearchBoxId + " div.column-inner").each(function (i, e) {
487            querystringHelper.addKey(queryStrings, "adults" + (i + 1), extractNumber($(e).find("span.column-adult .ui-selectmenu-text")));
488            querystringHelper.addKey(queryStrings, "children" + (i + 1), extractNumber($(e).find("span.column-child .ui-selectmenu-text")));
489        });
490
491        if (simpleVersion !== null && simpleVersion !== "" && simpleVersion !== undefined) {
492            querystringHelper.addKey(queryStrings, "simpleversion", simpleVersion);
493        }
494
495        //This is necessary in order to cater for situations where the booking pages are being served via the SearchSystem
496        if ($("#ref").length > 0 && $("#ref").val().length > 0) {
497            querystringHelper.addKey(queryStrings, "ref", $("#ref").val());
498        }
499
500        handlePromotionsRequestParameters(originalQueryString, queryStrings);
501
502        querystringHelper.addRandomizer(queryStrings);
503
504        searchUrl += querystringHelper.toString(queryStrings);
505
506        //reload browser to the search url
507        window.location.href = searchUrl;
508    }
509
510    function handlePromotionsRequestParameters(originalQueryString, queryStrings) {
511        //clear the promo code parameter
512        querystringHelper.deleteKey(queryStrings, "pce");
513        //see if promo code has to be submited fresh
514        var promotionCodeElement = $("#pce");
515        if (promotionCodeElement.length > 0) {
516            querystringHelper.addKey(queryStrings, "pce", promotionCodeElement.val());
517        }
518
519        //clear the promo instant deal parameter
520        querystringHelper.deleteKey(queryStrings, "peid");
521        //see if promo instant deal has to be submited fresh
522        var promotionEnableDealsElement = $("#peid");
523        if (promotionEnableDealsElement.length > 0 && promotionEnableDealsElement.val() != null && promotionEnableDealsElement.val() !== "") {
524            querystringHelper.addKey(queryStrings, "peid", promotionEnableDealsElement.val());
525        }
526    }
527
528    ///<summary>
528Construct the search URL base on the base URL and the selected parameters</summary>
529    function showStartDateCalendar(e) {
530        if (!$viewportWidth < 768) {
531            //smaller than ipad
532            eviivo.smoothScrolling.smoothScrollHandler(e, function () {
533                $startDate.datepicker("show");
534            }, this);
535        }
536    }
537
538    ///<summary>initialize the serach form based on criteria options we have (either from query string, from property setup or from our own defaults)</summary>
539    function initSearchForm() {
540
541        //pass through all occupancy groups
542        $.each(options.criteria.occupancy, function (index, value) {
543            //construct extra occupancy group selectors in case it's needed
544            while (index > 0 && index > $occupancySelectors.length - 1) {
545                addRoomClickHandler();
546            }
547            $($occupancySelectors[index].adults).val(value.adults);
548            $($occupancySelectors[index].adults).selectmenu("refresh");
549            $($occupancySelectors[index].children).val(value.children);
550            $($occupancySelectors[index].children).selectmenu("refresh");
551        });
552
553        occupancySelectHandler();
554    }
555
556    ///<summary>Datepicker select handler for start date</summary>
557    function startDateSelectHandler(date, instance) {
558        //grab selected date and add extra 24 hours
559        var selectedDate = new Date(instance.selectedYear, instance.selectedMonth, parseInt(instance.selectedDay), 0, 0, 0, 0);
560        var minEndDate = new Date(selectedDate).addHours(24);
561
562        //set the minDate for the endDate calendar
563        $endDate.datepicker("option", { "minDate": minEndDate });
564
565        //auto show the end date calendar (delay of 100ms because of jquery show effects on datepicker)
566        setTimeout(function () {
567            $endDate.datepicker("show");
568            $endDate.datepicker("setDate", minEndDate);
569        }, 100);
570
571        // If yellow tooltip exists & it's visible
572        if ($datePickerSelectionToolTip.length > 0 && $datePickerSelectionToolTip.is(':visible')) {
573            clearDatePickerTooltip();
574        }
575    }
576
577    ///<summary>Datepicker select handler for end date</summary>
578    function endDateSelectHandler(date, instance) {
579        if ($startDate.val() === "") {
580            //auto show the end date calendar (delay of 100ms because of jquery show effects on datepicker)
581            setTimeout(function () {
582                $startDate.datepicker("show");
583            }, 100);
584        } else {
585            //focus on done button
586            $firstAdultsOccupancy.focus();
587        }
588        // If yellow tooltip exists & it's visible
589        if ($datePickerSelectionToolTip.length > 0 && $datePickerSelectionToolTip.is(':visible')) {
590            clearDatePickerTooltip();
591        }
592
593    }
594
595    ///<summary>helper function to extract number from occupancy selector text (adult or child)</summary>
596    function extractNumber(selector) {
597        return parseInt(selector.text().slice(0, 2).trim());
598    }
599
600    ///<summary>extend Date javascript object and add extra function "addHours"</summary>
601    Date.prototype.addHours = function (hours) {
602        this.setHours(this.getHours() + hours);
603        return this;
604    };
605
606    ///<summary>Expose the internal "private" methods for external use (make them public)</summary>
607    return {
608        init: init,
609        triggerSearch: triggerSearch
610    };
611}(jQuery);

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.