1/// watches for changes in the class of an element 2class ClassWatcher { 3 4 constructor(targetNode, classToWatch, classAddedCallback, classRemovedCallback) { 5 this.targetNode = targetNode 6 this.classToWatch = classToWatch 7 this.classAddedCallback = classAddedCallback 8 this.classRemovedCallback = classRemovedCallback 9 this.observer = null 10 this.lastClassState = targetNode.classList.contains(this.classToWatch) 11 12 this.init() 13 } 14 15 init() { 16 this.observer = new MutationObserver(this.mutationCallback) 17 this.observe() 18 } 19 20 observe() { 21 this.observer.observe(this.targetNode, { attributes: true }) 22 } 23 24 disconnect() { 25 this.observer.disconnect() 26 } 27 28 mutationCallback = mutationsList => { 29 for (let mutation of mutationsList) { 30 if (mutation.type === 'attributes' && mutation.attributeName === 'class') { 31 let currentClassState = mutation.target.classList.contains(this.classToWatch) 32 if (this.lastClassState !== currentClassState) { 33 this.lastClassState = currentClassState 34 if (currentClassState) { 35 this.classAddedCallback() 36 } 37 else { 38 this.classRemovedCallback() 39 } 40 } 41 } 42 } 43 } 44} 45 46 47// Booking Modal & Widget Month&Day 48 49/// all labels used here are defined in the .cshtml file due to translations 50 51/// booking vars 52var _jabook_hotelname = _jabook_allHotelsId; /// global var 53var _jabook_hotelid = ""; 54var _jabook_start_date = ""; 55var _jabook_end_date = ""; 56var _jabook_adult_count = 2; 57var _jabook_child_count = 0; 58var _jabook_no_of_rooms = 1; 59 60document.addEventListener("DOMContentLoaded", function () { 61 62 const hotelPopup = document.querySelector('.hotel-popup'); 63 const hotelMobilePopup = document.querySelector('.mobile-hotel-selector'); 64 const hotelMobilePopupClose = hotelMobilePopup.querySelector('.close-mobile-popup'); 65 const hotelSelector = document.querySelector('.hotel-selector'); 66 const widget = document.querySelector('.reservation-search'); 67 const widgetUI = document.querySelector('.widget-container'); 68 const hotelListItems = document.querySelectorAll('.hotel_list_item'); 69 const datePopup = document.querySelector('.date-popup'); 70 const dateSelector = document.querySelector('.date-selector'); 71 const dateMobilePopup = document.querySelector('.mobile-date-selector'); 72 const dateMobilePopupClose = dateMobilePopup.querySelector('.close-mobile-popup'); 73 const selectedDatebutton = dateMobilePopup.querySelector('.select-date-button'); 74 const paxPopup = document.querySelector('.pax-popup'); 75 const paxMobilePopup = document.querySelector('.mobile-guest-selector'); 76 const paxSelector = document.querySelector('.guest-selector'); 77 const guestRooms = document.querySelector('.pax-popup .rooms'); 78 const addRoom = document.querySelectorAll('.addroom'); 79 const paxMobilePopupClose = paxMobilePopup.querySelector('.close-mobile-popup'); 80 const guestClearBtn = paxMobilePopup.querySelector('.guest-clear-btn'); 81 const mobileGuestRooms = paxMobilePopup.querySelector('.mobile-guest-selector .rooms'); 82 const findrooms = document.querySelectorAll('.findrooms'); 83 const stayCalendar = document.querySelectorAll('.stayCalendar'); 84 const PromocodeInput = document.querySelectorAll('.promocode_input_widget'); 85 var mobileBookingwidget = document.querySelector('.mobile-bookingwidget-selector'); 86 var hotelwidget = document.querySelector('.hotel-selection'); 87 var datewidget = document.querySelector('.date-selection'); 88 var guestwidget = document.querySelector('.guest-selection'); 89 var codewidget = document.querySelector('.code-input-selection'); 90 var isMobile = window.innerWidth < 1199 ? true : false; 91 var isTab = window.innerWidth < 699 ? true : false; 92 93 var code_type = ""; 94 var code_value = ""; 95 var selected_codetype = ""; 96 var selected_codevalue = ""; 97 98 var rate_plan_code = ""; 99 var prices = {}; 100 var status = {}; 101 var minlength = {}; 102 let displayedMonths = new Set(); 103 var offset = 120;
104 let currentDate = new Date(moment().utcOffset(offset).format("YYYY/MM/DD")); 105 let automaticallySelectedHotel = false; 106 107 function checkResolution() { 108 isMobile = window.innerWidth < 1199 ? true : false; 109 isTab = window.innerWidth < 699 ? true : false; 110 if (_jabook_start_date == "" && _jabook_end_date == "") { 111 if (isMobile) 112 document.querySelector('.selected-date').textContent = checkinmobile_text; 113 else 114 document.querySelector('.selected-date').textContent = checkin_text; 115 } 116 } 117 118 // Run on page load 119 checkResolution(); 120 121 // This will return the current date adjusted for the UTC offset 122 // Listen to the window resize event and update isMobile 123 //window.addEventListener('resize', checkResolution); 124 let date_picker_elements = document.querySelectorAll('.home-reservation-search .datepicker'); 125 126 let datepickers = Array.from(date_picker_elements).map(date_picker_element => { 127 return new easepick.create({ 128 element: date_picker_element, 129 css: [ 130 'https://cdn.jsdelivr.net/npm/@easepick/[email protected]/dist/index.css', 131 '/Mvc/Views/ReservationForm/theme-easepick.css' 132 ], 133 inline: true, 134 alwaysOpen: true, 135 calendars: 2, 136 grid: isTab ? 1 : 2, 137 format: 'DD MMM YYYY', 138 plugins: ['RangePlugin', 'LockPlugin'], 139 RangePlugin: { 140 tooltip: false, 141 locale: { 142 one: "night", 143 other: "nights", 144 }, 145 }, 146 lang: 'en', 147 LockPlugin: { 148 minDate: currentDate, 149 maxDate: moment().add(1, 'year').toDate(), 150 }, 151 setup(picker) { 152 // Set initial dates if present 153 // if (_jabook_start_date && _jabook_end_date) { 154 // 155 // } 156 picker.on("select", (e) => { 157 158 let start, end; 159 if (e.detail.date) { 160 start = e.detail.date.toLocaleDateString("en-US", { day: "2-digit", month: "2-digit", year: "numeric" }); 161 end = e.detail.date.toLocaleDateString("en-US", { day: "2-digit", month: "2-digit", year: "numeric" }); 162 } else { 163 start = e.detail.start.toLocaleDateString("en-US", { day: "2-digit", month: "2-digit", year: "numeric" }); 164 end = e.detail.end.toLocaleDateString("en-US", { day: "2-digit", month: "2-digit", year: "numeric" }); 165 } 166 167 // Convert start and end to Moment objects for formatting 168 let startMoment = moment(start, 'MM/DD/YYYY'); 169 let endMoment = moment(end, 'MM/DD/YYYY'); 170 171 datepickers.forEach(p => { 172 p.setStartDate(startMoment.toDate()); // Set the start date 173 p.setEndDate(endMoment.toDate()); // Set the end date 174 }); 175 176 document.querySelector('.selected-date').textContent = 177 `${startMoment.format('DD/MM/YYYY')} - ${endMoment ? endMoment.format('DD/MM/YYYY') : 'Check Out'}`; 178 document.querySelector('.selected-date').classList.add('visible-date'); 179 document.querySelectorAll('.mobile-popup-wrapper .date-selector-title-text').forEach(selectedDate => { 180 selectedDate.textContent = 181 `${startMoment.format('DD/MM/YYYY')} - ${endMoment ? endMoment.format('DD/MM/YYYY') : 'Check Out'}`; 182 }) 183 _jabook_start_date = startMoment.format('YYYY-MM-DD'); 184 _jabook_end_date = endMoment.format('YYYY-MM-DD'); 185 const nightDifference = endMoment.diff(startMoment, 'days'); // Calculate the difference in nights 186 var var_night = nightDifference > 1 ? nightsVar : nightVar; 187 document.querySelectorAll('.night_var_widget').forEach(nightcount => { 188 nightcount.classList.remove('d-none'); 189 nightcount.innerText = nightDifference + var_night; 190 }); 191 document.querySelector('.date-clear-btn').classList.remove('d-none'); 192 checkDateValidity(_jabook_start_date, _jabook_end_date); 193 194 }); 195 picker.on('view', (evt) => { 196 197 if (dateSelector.classList.contains('errorbox')) 198 dateSelector.classList.remove('errorbox'); 199 200 if (_jabook_start_date && _jabook_end_date) { 201 var difference_in_days = moment(_jabook_end_date).diff(moment(_jabook_start_date), 'days'); 202 if (_jabook_start_date === _jabook_end_date && status[_jabook_start_date] === "Only-Check-out") { 203 showCalendarError(checkin_unavail); 204 } else if (_jabook_start_date === _jabook_end_date) { 205 showCalendarError(calendar_minerror); 206 } else if (status[_jabook_end_date] === "Only-Check-in") { 207 showCalendarError(checkout_unavail); 208 } else if (status[_jabook_start_date] === "Only-Check-out") { 209 showCalendarError(checkin_unavail); 210 } else if (difference_in_days < minlength[_jabook_start_date]) { 211 showCalendarError(minLength_error_message + " " + minlength[_jabook_start_date] + " " + nights_stay_var); 212 } 213 } 214 }); 215 }, 216 }); 217 });
218 219 // Hotel Popup functions 220 window.addEventListener('scroll', function () { 221 var scrollThreshold = 200; 222 if (isMobile) { 223 scrollThreshold = 20; 224 if (window.scrollY) { 225 widget.classList.add('active-scroll', 'fixed-scroll'); 226 } else { 227 widget.classList.remove('active-scroll', 'fixed-scroll'); 228 } 229 230 } 231 }); 232 233 window.addEventListener('scroll', function () { 234 if (window.scrollY > 0 && window.scrollX > 0) 235 hotelPopup.classList.add('d-none'); 236 237 const scrollThreshold = window.innerHeight; 238 if (!isMobile) { 239 const scrollThreshold = widget.getBoundingClientRect().top; 240 if (scrollThreshold <= 0 && window.scrollY > window.innerHeight * 0.8) { 241 widget.classList.add('fixed-scroll', 'active-scroll'); 242 const topPosition = widgetUI.getBoundingClientRect().bottom; 243 hotelPopup.style.top = topPosition + 2 + 'px'; 244 hotelPopup.style.position = 'fixed'; 245 246 if ($('.reservation-in').css("display") != "none") { 247 $("header").removeClass("non-sticky"); 248 } 249 else { 250 $("header").addClass("non-sticky"); 251 } 252 /// make the header non-fixed 253 254 } else { 255 widget.classList.remove('fixed-scroll', 'active-scroll'); 256 hotelPopup.style.position = 'absolute'; 257 hotelPopup.style.top = 'unset'; 258 259 $("header").removeClass("non-sticky"); 260 } 261 } 262 }); 263 264 // CHILD AGE DROPDOWNS 265 //$("#childrenSelect").on("change", function () { 266 // const count = parseInt($(this).val(), 10); 267 // const $container = $("#childAgeList"); 268 269 // $container.empty(); // reset 270 271 // for (let i = 0; i < count; i++) { 272 // // Build <li> with child age dropdown 273 // const $li = $(` 274 // <li> 275 // <div class="children-age"> 276 // <select class="child-age-select"> 277 // <option value="">Age</option> 278 // </select> 279 // </div> 280 // </li> 281 // `); 282 283 // // Append age options 0â11 284 // for (let age = 0; age < 12; age++) { 285 // $li.find("select").append( 286 // $("<option>", { value: age, text: age }) 287 // ); 288 // } 289 290 // $container.append($li); 291 // } 292 //}); 293 294 hotelListItems.forEach(item => { 295 296 // check if item has a role=button and only then add the click event 297 if ($(item).attr("role") !== "button") { 298 return; 299 } 300 301 item.addEventListener('click', function () { 302 let hotelId = item.getAttribute('data-id'); 303 hotelSelector.setAttribute('data-id', hotelId); 304 hotelPopup.classList.add('d-none'); 305 hotelSelector.querySelector('.selected-hotel').textContent = item.textContent; 306 hotelMobilePopup.querySelector('.hotel-selector-title-text').textContent = item.textContent; 307 document.querySelector('.mobile-bookingwidget-selector .hotel-selector-title-text').textContent = item.textContent; 308 _jabook_hotelname = item.textContent.trim(); 309 310 _jabook_hotelid = hotelId; 311 312 currentDate = new Date(moment().format("YYYY/MM/DD")); 313 314 initaiatecalendar(); 315 if (isMobile) { 316 if (automaticallySelectedHotel) { 317 /// do not open the date popup if the hotel is automatically selected 318 /// because of the url that we are on 319 automaticallySelectedHotel = false; 320 return; 321 } 322 hotelMobilePopup.classList.add('d-none'); 323 dateMobilePopup.classList.remove('d-none'); 324 } 325 if (_jabook_hotelid == 'all')
326 datepickers.forEach(picker => { 327 picker.renderAll(); 328 }); 329 }); 330 }); 331 332 function dNoneClassAdded() { 333 $("header").css("z-index", 801); 334 } 335 336 function dNoneClassRemoved() { 337 $("header").css("z-index", 788); 338 } 339 340 // watch for a specific class change 341 let classWatcherHotel = new ClassWatcher(hotelPopup, 'd-none', dNoneClassAdded, dNoneClassRemoved); 342 let classWatcherDate = new ClassWatcher(datePopup, 'd-none', dNoneClassAdded, dNoneClassRemoved); 343 344 345 hotelSelector.addEventListener('click', function () { 346 347 if (isMobile) 348 hotelMobilePopup.classList.toggle('d-none') 349 else { 350 hotelPopup.classList.toggle('d-none'); 351 352 if (window.scrollY < window.innerHeight * 0.8) { 353 window.scrollTo(0, 0); 354 } else { 355 if (widget.classList.contains('active-scroll')) { 356 const topPosition = widgetUI.getBoundingClientRect().bottom; 357 hotelPopup.style.top = topPosition + 2 + 'px'; 358 hotelPopup.style.position = 'fixed'; 359 } else { 360 hotelPopup.style.position = 'absolute'; 361 hotelPopup.style.top = 'unset'; 362 } 363 } 364 } 365 }); 366 367 368 $('.hotel_list_item').click(function () { 369 $('.individualHotels_Dropdown-Menu.show').removeClass('show') 370 $('.allHotels_Dropdown-Menu.show').removeClass('show') 371 }); 372 373 374 $('#hotel_dropdown .modal-content .hotel-mobile-dropdown .dropdown-menu .dropdown-item').click(function () { 375 $('#navbarContent .hoteldropdown .hotel-dropdown-mobile span').text($(this).text()); 376 $('#hotel_dropdown .modal-content .hotel-mobile-dropdown .dropdown-toggle span').text($(this).text()); 377 $('#hotel_dropdown').modal('hide'); 378 }); 379 380 document.addEventListener('click', function (event) { 381 if (!hotelPopup.contains(event.target) && !hotelSelector.contains(event.target)) { 382 hotelPopup.classList.add('d-none'); 383 } 384 }); 385 hotelMobilePopupClose.addEventListener('click', function (event) { 386 hotelMobilePopup.classList.add('d-none'); 387 }); 388 389 function initaiatecalendar() { 390 prices = {}; 391 status = {}; 392 minlength = {}; 393 // clear the displayed months 394 displayedMonths = new Set(); 395 stayCalendar.forEach(calenar => { 396 if (!calenar.classList.contains('d-none')) 397 calenar.classList.add('d-none'); 398 }); 399 generateFirstMonthData(); 400 } 401 402 function generateFirstMonthData() { 403 var pricestext = document.querySelector('.prices-text'); 404 var pricestextmobile = document.querySelector('.currency-text'); 405 if (_jabook_hotelid != null && _jabook_hotelid != "all" && _jabook_hotelid != "") { 406 const from_date = moment(currentDate).format('YYYY-MM-DD'); 407 const to_date = moment(currentDate).endOf('month').format("YYYY-MM-DD"); 408 409 } else { 410 if (!pricestext.classList.contains('d-none')) 411 document.querySelector('.prices-text').classList.add('d-none'); 412 if (!pricestextmobile.classList.contains('d-none')) 413 pricestextmobile.classList.add('d-none'); 414 } 415 } 416 417 dateSelector.addEventListener('click', function () { 418 var dpopup = $(".date-popup"); 419 if (isMobile) { 420 dateMobilePopup.classList.toggle('d-none'); 421 datepickers.forEach(picker => { 422 picker.renderAll(); 423 }); 424 } 425 else { 426 datePopup.classList.toggle('d-none'); 427 if (window.scrollY < window.innerHeight * 0.8) { 428 window.scrollTo(0, 0); 429 } 430 if (!dpopup.hasClass("d-none")) { 431 $("header").css("z-index", 788); 432 } 433 else { 434 $("header").css("z-index", 801); 435 } 436 437 } 438 });
439 document.addEventListener('click', function (event) { 440 if (!datePopup.contains(event.target) && !dateSelector.contains(event.target)) { 441 datePopup.classList.add('d-none'); 442 } 443 444 }); 445 dateMobilePopupClose.addEventListener('click', function (event) { 446 dateMobilePopup.classList.add('d-none'); 447 }); 448 449 $(document).on("click", ".hotel-popup-header .nav-item:first button.active", function () { 450 451 /// if the user clicks on the All Hotels tab, we clear the selected hotel 452 _jabook_hotelname = _jabook_allHotelsId; 453 hotelSelector.querySelector('.selected-hotel').textContent = all_hotels_var; 454 }); 455 456 function checkDateValidity(start, end) { 457 var difference_in_days = moment(end).diff(moment(start), 'days'); 458 if (start === end && status[start] === "Only-Check-out") { 459 showCalendarError(checkin_unavail); 460 } else if (start === end) { 461 showCalendarError(calendar_minerror); 462 } else if (status[end] === "Only-Check-in") { 463 showCalendarError(checkout_unavail); 464 } else if (status[start] === "Only-Check-out") { 465 showCalendarError(checkin_unavail); 466 } else if (difference_in_days < minlength[start]) { 467 showCalendarError(minLength_error_message + " " + minlength[start] + " " + nights_stay_var); 468 } else { 469 hideCalendarError(); 470 } 471 } 472 473 function showCalendarError(message) { 474 stayCalendar.forEach(calenar => { 475 calenar.classList.remove('d-none'); 476 calenar.innerHTML = ` 477 <div class="calendar-error-msg mb-0" role="alert"> 478 <p> 479 <i class="fal fa-exclamation-triangle px-1"></i>
480 <span class="error-message">${message}</span> 481 </p> 482 </div>`; 483 }); 484 findrooms.forEach(findRoom => { 485 findRoom.classList.add('disabled'); 486 findRoom.setAttribute('disabled', 'disabled'); 487 }); 488 dateSelector.classList.add('errorbox'); 489 selectedDatebutton.classList.add('d-none'); 490 // selectedDatebutton.setAttribute('disabled', 'disabled'); 491 } 492 493 function hideCalendarError() { 494 stayCalendar.forEach(calenar => { 495 calenar.classList.add('d-none'); 496 }); 497 findrooms.forEach(findRoom => { 498 findRoom.classList.remove('disabled'); 499 findRoom.removeAttribute('disabled'); 500 }); 501 selectedDatebutton.classList.remove('d-none'); 502 document.querySelector('.date-popup').classList.add('d-none'); 503 if (dateSelector.classList.contains('errorbox')) 504 dateSelector.classList.remove('errorbox'); 505 } 506 function clearDatePicker() { 507 datepickers.forEach(picker => { 508 picker.clear(); // Clear the selected date 509 }); 510 // Reset the displayed date text 511 if (isMobile) 512 document.querySelector('.selected-date').textContent = checkinmobile_text; 513 else 514 document.querySelector('.selected-date').textContent = checkin_text; 515 document.querySelector('.selected-date').classList.remove('visible-date'); 516 document.querySelectorAll('.mobile-popup-wrapper .date-selector-title-text').forEach(selectedDate => { 517 selectedDate.textContent = checkin_text; 518 }) 519 document.querySelectorAll('.night_var_widget').forEach(nightcount => { 520 nightcount.classList.add('d-none'); 521 }); 522 document.querySelector('.date-clear-btn').classList.add('d-none'); 523 524 _jabook_start_date = ""; 525 _jabook_end_date = ""; 526 stayCalendar.forEach(calenar => { 527 if (!calenar.classList.contains('d-none')) 528 calenar.classList.add('d-none'); 529 }); 530 selectedDatebutton.classList.add('d-none'); 531 } 532 533 document.querySelector('.date-clear-btn').addEventListener('click', function () { 534 clearDatePicker(); 535 }); 536 537 selectedDatebutton.addEventListener('click', function () { 538 dateMobilePopup.classList.add('d-none'); 539 mobileBookingwidget.classList.remove('d-none'); 540 }); 541 542 // Pax Popup functions 543 paxSelector.addEventListener('click', function () { 544 if (isMobile) 545 paxMobilePopup.classList.toggle('d-none'); 546 else { 547 paxPopup.classList.toggle('d-none'); 548 if (window.scrollY < window.innerHeight * 0.8) { 549 window.scrollTo(0, 0); 550 } 551 } 552 }); 553 554 document.addEventListener('click', function (event) { 555 if (!paxPopup.contains(event.target) && !paxSelector.contains(event.target) && !event.target.closest('.btn-remove-room')) { 556 paxPopup.classList.add('d-none'); 557 } 558 }); 559 paxMobilePopupClose.addEventListener('click', function () { 560 paxMobilePopup.classList.add('d-none'); 561 }); 562 563 addRoom.forEach(addRoombtn => { 564 addRoombtn.addEventListener('click', function () { 565 if (window.scrollY < window.innerHeight * 0.8) { 566 window.scrollTo(0, 0); 567 } 568 if (_jabook_no_of_rooms == 1) { 569 [guestRooms, mobileGuestRooms].forEach(container => { 570 const dropdownDiv = container.querySelector('.room:first-child .room-header'); 571 dropdownDiv.classList.remove('d-none'); 572 dropdownDiv.classList.add('d-flex'); 573 }); 574 } 575 576 if (_jabook_no_of_rooms < 9) { 577 const newRoomNumber = _jabook_no_of_rooms + 1; 578 addnewroom(newRoomNumber); 579 addnewroomMobile(newRoomNumber); 580 if (addRoombtn.classList.contains('desktop')) 581 updatechildadultcount('desktop'); 582 else 583 updatechildadultcount('mobile'); 584 585 // Scroll to the bottom of the room lists
586 [guestRooms, mobileGuestRooms].forEach(container => { 587 container.scrollTo({ 588 top: paxPopup.scrollHeight, 589 behavior: 'smooth' 590 }); 591 }); 592 paxPopup.scrollTop = paxPopup.scrollHeight; 593 paxMobilePopup.querySelector('.overflow-wrapper').scrollTop = paxMobilePopup.querySelector('.overflow-wrapper').scrollHeight; 594 } 595 596 if (_jabook_no_of_rooms == 8) { 597 addRoom.forEach(addRoombtn => { 598 addRoombtn.parentElement.classList.add('d-none'); 599 }); 600 } 601 _jabook_no_of_rooms++; 602 }); 603 }); 604 605 function addnewroom(newRoomNumber) { 606 const newRoom = document.createElement('div'); 607 newRoom.classList.add('room'); 608 newRoom.setAttribute('data-room', newRoomNumber); 609 610 newRoom.innerHTML = ` 611 <div class="room-header d-flex align-items-center mt-3"> 612 <div class="room-title">${room_var} ${newRoomNumber}</div> 613 <span class="btn-remove-room" aria-label="Remove room"> 614 <i class="fa fa-trash trash_widget"></i> 615 </span> 616 </div> 617 <div class="guest-counter d-flex justify-content-between align-items-center py-1 my-3"> 618 <label class="guest-label mb-0">${adult_text} (12+)</label> 619 <div class="counter-box d-flex align-items-center"> 620 <span class="btn_counter ag-minus disabled" data-action="minus"> 621 <i class="fa fa-minus-circle"></i> 622 </span> 623 <span class="adult-counter count b4">1</span> 624 <span class="btn_counter ag-plus" data-action="plus"> 625 <i class="fa fa-plus-circle"></i> 626 </span> 627 </div> 628 </div> 629 <div class="guest-counter d-flex justify-content-between align-items-center py-1 my-3"> 630 <label class="guest-label mb-0">${children_text} (4-11)</label> 631 <div class="counter-box d-flex align-items-center"> 632 <span class="btn_counter cg-minus disabled" data-action="minus"> 633 <i class="fa fa-minus-circle"></i> 634 </span> 635 <span class="child-counter count b4">0</span> 636 <span class="btn_counter cg-plus" data-action="plus"> 637 <i class="fa fa-plus-circle"></i> 638 </span> 639 </div> 640 </div> 641 `; 642 643 guestRooms.appendChild(newRoom); 644 } 645 function addnewroomMobile(newRoomNumber) { 646 const newRoom = document.createElement('div'); 647 newRoom.classList.add('room', 'mb-2', 'bg-grey', 'rounded-8px', 'py-2'); 648 newRoom.setAttribute('data-room', newRoomNumber); 649 650 newRoom.innerHTML = ` 651 <div class="px-4 room-header align-items-center d-flex mt-2"> 652 <div class="room-title">${room_var} ${newRoomNumber}</div> 653 <span class="btn-remove-room" aria-label="Remove room"> 654 <i class="fa fa-trash trash_widget"></i> 655 </span> 656 </div> 657 <div class="d-flex justify-content-between align-items-center"> 658 <div class="guest-counter w-100 py-1"> 659 <label class="guest-label mb-2 px-4">${adult_text} (12+)</label> 660 <div class="counter-box d-flex align-items-center justify-content-between px-4"> 661 <span class="btn_counter ag-minus disabled" data-action="minus"> 662 <i class="fa fa-minus-circle"></i> 663 </span> 664 <span class="adult-counter count b4">1</span> 665 <span class="btn_counter ag-plus" data-action="plus"> 666 <i class="fa fa-plus-circle"></i> 667 </span> 668 </div> 669 </div> 670 <div style="background: #25282D29; width: 1px; height: 48px;"></div> 671 <div class="guest-counter w-100 py-1"> 672 <label class="guest-label mb-2 px-4">${children_text} (4-11)</label> 673 <div class="counter-box d-flex align-items-center justify-content-between px-4">
674 <span class="btn_counter cg-minus disabled" data-action="minus"> 675 <i class="fa fa-minus-circle"></i> 676 </span> 677 <span class="child-counter count b4">0</span> 678 <span class="btn_counter cg-plus" data-action="plus"> 679 <i class="fa fa-plus-circle"></i> 680 </span> 681 </div> 682 </div> 683 </div> 684 `; 685 686 mobileGuestRooms.appendChild(newRoom); 687 } 688 689 function updatechildadultcount(resolution) { 690 let adult_counters; 691 let child_counters; 692 if (resolution == 'desktop') { 693 adult_counters = guestRooms.querySelectorAll('.adult-counter'); 694 child_counters = guestRooms.querySelectorAll('.child-counter'); 695 } 696 else { 697 adult_counters = mobileGuestRooms.querySelectorAll('.adult-counter'); 698 child_counters = mobileGuestRooms.querySelectorAll('.child-counter'); 699 } 700 let adult_totalcount = 0; 701 let child_totalcount = 0; 702 703 adult_counters.forEach(function (item) { 704 adult_totalcount += parseInt(item.innerText); 705 }); 706 child_counters.forEach(function (item) { 707 child_totalcount += parseInt(item.innerText); 708 }); 709 710 _jabook_adult_count = adult_totalcount; 711 _jabook_child_count = child_totalcount; 712 paxSelector.querySelector('.selected-guest').textContent = `${adult_totalcount} ${adult_text}, ${child_totalcount} ${child_text}`; 713 document.querySelectorAll('.guest-selected-title-text').forEach(guest => { 714 guest.textContent = `${adult_totalcount} ${adult_text}, ${child_totalcount} ${child_text}`; 715 }); 716 717 } 718 719 // Desktop 720 guestRooms.addEventListener('click', function (event) { 721 const target = event.target; 722 // find the data-room attribute value 723 cuurentroomnumber = target.closest('.room').getAttribute('data-room'); 724 const counterBox = target.closest('.counter-box'); 725 const mobileRoom = mobileGuestRooms.querySelector(`.room[data-room="${cuurentroomnumber}"]`); 726 727 728 if (counterBox) { 729 const counter = counterBox.querySelector('.count'); 730 const isAdult = counter.classList.contains('adult-counter'); 731 const isPlus = target.closest('[data-action="plus"]'); 732 const isMinus = target.closest('[data-action="minus"]'); 733 734 if (isAdult) 735 mobileCounter = mobileRoom.querySelector('.counter-box .adult-counter'); 736 else 737 mobileCounter = mobileRoom.querySelector('.counter-box .child-counter'); 738 739 const mobileMinBtn = mobileCounter.closest('.counter-box').querySelector('[data-action="minus"]'); 740 const mobilePlusBtn = mobileCounter.closest('.counter-box').querySelector('[data-action="plus"]'); 741 742 if (isPlus || isMinus) { 743 let count = parseInt(counter.innerText); 744 const minBtn = counterBox.querySelector('[data-action="minus"]'); 745 const plusBtn = counterBox.querySelector('[data-action="plus"]'); 746 747 if (isPlus) { 748 count++; 749 counter.innerText = count; 750 minBtn.classList.remove('disabled'); 751 mobileCounter.innerText = count; 752 mobileMinBtn.classList.remove('disabled'); 753 if (count == 10) { 754 plusBtn.classList.add('disabled'); 755 mobilePlusBtn.classList.add('disabled'); 756 } 757 } else if (isMinus && count > (isAdult ? 1 : 0)) { 758 count--; 759 counter.innerText = count; 760 mobileCounter.innerText = count; 761 if (count === (isAdult ? 1 : 0)) { 762 minBtn.classList.add('disabled'); 763 mobileMinBtn.classList.add('disabled'); 764 } 765 if (count < 10) { 766 if (plusBtn.classList.contains('disabled')) 767 plusBtn.classList.remove('disabled'); 768 if (mobilePlusBtn.classList.contains('disabled')) 769 mobilePlusBtn.classList.remove('disabled'); 770 } 771 772 773 } 774 775 updatechildadultcount('desktop'); 776 } 777 } 778 779 if (target.closest('.btn-remove-room')) { 780 event.stopPropagation(); // Add this line to prevent event bubbling 781 const room = target.closest('.room'); 782 const mobileroom = mobileGuestRooms.querySelector(`.room[data-room="${cuurentroomnumber}"]`); // 783 if (mobileroom && room && guestRooms.children.length > 1) { 784 room.remove(); 785 mobileroom.remove(); // Remove the room 786 updatechildadultcount('desktop'); 787 _jabook_no_of_rooms--; 788 addRoom.forEach(addRoombtn => { 789 if (addRoombtn.parentElement.classList.contains('d-none')) 790 addRoombtn.parentElement.classList.remove('d-none'); 791 }); 792 793 renumberroom(); 794 } 795 } 796 });
797 // Mobile 798 mobileGuestRooms.addEventListener('click', function (event) { 799 const target = event.target; 800 cuurentroomnumber = target.closest('.room').getAttribute('data-room'); 801 const counterBox = target.closest('.counter-box'); 802 const desktopRoom = guestRooms.querySelector(`.room[data-room="${cuurentroomnumber}"]`); 803 804 if (counterBox) { 805 const counter = counterBox.querySelector('.count'); 806 const isAdult = counter.classList.contains('adult-counter'); 807 const isPlus = target.closest('[data-action="plus"]'); 808 const isMinus = target.closest('[data-action="minus"]'); 809 let desktopCounter; 810 if (isAdult) 811 desktopCounter = desktopRoom.querySelector('.counter-box .adult-counter'); 812 else 813 desktopCounter = desktopRoom.querySelector('.counter-box .child-counter'); 814 815 const desktopMinBtn = desktopCounter.closest('.counter-box').querySelector('[data-action="minus"]'); 816 817 const desktopPlusBtn = desktopCounter.closest('.counter-box').querySelector('[data-action="plus"]'); 818 if (isPlus || isMinus) { 819 let count = parseInt(counter.innerText); 820 const minBtn = counterBox.querySelector('[data-action="minus"]'); 821 const plusBtn = counterBox.querySelector('[data-action="plus"]'); 822 823 if (isPlus) { 824 count++; 825 counter.innerText = count; 826 minBtn.classList.remove('disabled'); 827 desktopCounter.innerText = count; 828 desktopMinBtn.classList.remove('disabled'); 829 if (count == 10) { 830 plusBtn.classList.add('disabled'); 831 desktopPlusBtn.classList.add('disabled'); 832 } 833 } else if (isMinus && count > (isAdult ? 1 : 0)) { 834 count--; 835 counter.innerText = count; 836 desktopCounter.innerText = count; 837 if (count === (isAdult ? 1 : 0)) { 838 minBtn.classList.add('disabled'); 839 desktopMinBtn.classList.add('disabled'); 840 } 841 if (count < 10) { 842 if (plusBtn.classList.contains('disabled')) 843 plusBtn.classList.remove('disabled'); 844 if (desktopPlusBtn.classList.contains('disabled')) 845 desktopPlusBtn.classList.remove('disabled'); 846 } 847 } 848 849 updatechildadultcount('mobile'); // Update the total count for desktop 850 } 851 } 852 853 if (target.closest('.btn-remove-room')) { 854 event.stopPropagation(); // Prevent event bubbling 855 const room = target.closest('.room'); 856 const desktoproom = guestRooms.querySelector(`.room[data-room="${cuurentroomnumber}"]`); // 857 if (desktoproom && room && mobileGuestRooms.children.length > 1) { 858 room.remove(); 859 desktoproom.remove(); // Remove the room 860 updatechildadultcount('mobile'); // Update the total count for desktop 861 _jabook_no_of_rooms--; 862 addRoom.forEach(addRoombtn => { 863 if (addRoombtn.parentElement.classList.contains('d-none')) 864 addRoombtn.parentElement.classList.remove('d-none'); 865 }); 866 renumberroom(); 867 } 868 } 869 }); 870 function renumberroom() { 871 // Renumber the rooms for both desktop and mobile 872 [guestRooms, mobileGuestRooms].forEach(container => { 873 const rooms = container.querySelectorAll('.room'); 874 rooms.forEach((room, index) => { 875 const roomNumber = index + 1; 876 room.setAttribute('data-room', roomNumber); 877 room.querySelector('.room-title').textContent = `${room_var} ${roomNumber}`; 878 }); 879 // If only one room is left, add 'd-none' to the room-header 880 if (rooms.length === 1) { 881 const firstRoomHeader = rooms[0].querySelector('.room-header'); 882 firstRoomHeader.classList.add('d-none'); 883 firstRoomHeader.classList.remove('d-flex'); 884 } 885 }); 886 } 887 guestClearBtn.addEventListener('click', function (event) { 888 clearpaxdata(); 889 });
890 function clearpaxdata() { 891 // Clear all rooms except the first one 892 _jabook_no_of_rooms = 1; 893 [guestRooms, mobileGuestRooms].forEach(container => { 894 const rooms = container.querySelectorAll('.room'); 895 896 // Remove all rooms except the first 897 for (let i = 1; i < rooms.length; i++) { 898 if (rooms.length > 1) { 899 rooms[i].remove(); 900 } 901 } 902 // Set the first room to have 1 adult and 0 children 903 const firstRoom = rooms[0]; 904 const firstRoomHeader = rooms[0].querySelector('.room-header'); 905 firstRoomHeader.classList.add('d-none'); 906 firstRoomHeader.classList.remove('d-flex'); 907 firstRoom.querySelector('.adult-counter').innerText = '1'; 908 const adultCounterMinusBtn = firstRoom.querySelector('.adult-counter').closest('.counter-box').querySelector('[data-action="minus"]'); 909 if (adultCounterMinusBtn) { 910 adultCounterMinusBtn.classList.add('disabled'); 911 } 912 firstRoom.querySelector('.child-counter').innerText = '0'; 913 const childCounterMinusBtn = firstRoom.querySelector('.child-counter').closest('.counter-box').querySelector('[data-action="minus"]'); 914 if (childCounterMinusBtn) { 915 childCounterMinusBtn.classList.add('disabled'); 916 } 917 updatechildadultcount('mobile'); 918 }); 919 addRoom.forEach(addRoombtn => { 920 if (addRoombtn.parentElement.classList.contains('d-none')) 921 addRoombtn.parentElement.classList.remove('d-none'); 922 }); 923 } 924 925 document.querySelector('.mobile-guest-selector-done').addEventListener('click', function () { 926 paxMobilePopup.classList.add('d-none'); 927 mobileBookingwidget.classList.remove('d-none'); 928 }); 929 document.querySelector('.backtoguestwidget').addEventListener('click', function () { 930 paxMobilePopup.classList.add('d-none'); 931 mobileBookingwidget.classList.remove('d-none'); 932 }); 933 934 935 // Mobile Booking Widget 936 hotelwidget.addEventListener('click', function () { 937 mobileBookingwidget.classList.add('d-none'); 938 hotelMobilePopup.classList.remove('d-none'); 939 }); 940 datewidget.addEventListener('click', function () { 941 mobileBookingwidget.classList.add('d-none'); 942 dateMobilePopup.classList.remove('d-none'); 943 }); 944 guestwidget.addEventListener('click', function () { 945 mobileBookingwidget.classList.add('d-none'); 946 paxMobilePopup.classList.remove('d-none'); 947 }); 948 949 mobileBookingwidget.querySelector('.close-mobile-popup').addEventListener('click', function () { 950 mobileBookingwidget.classList.add('d-none'); 951 }); 952 mobileBookingwidget.querySelector('.widget-clear-btn').addEventListener('click', function () { 953 // clear hotels 954 if (!mobileBookingwidget.querySelector('.hotel-selection').classList.contains('disabled')) { 955 _jabook_hotelid = "all"; 956 _jabook_hotelname = _jabook_allHotelsId; 957 hotelSelector.querySelector('.selected-hotel').textContent = all_hotels_var; 958 hotelMobilePopup.querySelector('.hotel-selector-title-text').textContent = all_hotels_var; 959 document.querySelector('.mobile-bookingwidget-selector .hotel-selector-title-text').textContent = all_hotels_var; 960 } 961 }); 962 const popupWrapper = document.querySelector('.mobile-popup-wrapper'); 963 964 // Function to check if any immediate child div inside `mobile-popup-wrapper` is visible 965 function checkPopupVisibility() { 966 let isPopupVisible = false; 967 popupWrapper.querySelectorAll(':scope > div').forEach(div => { 968 if (!div.classList.contains('d-none')) { 969 isPopupVisible = true; 970 } 971 }); 972 document.body.style.overflow = isPopupVisible ? 'hidden' : ''; 973 } 974 const observer = new MutationObserver(checkPopupVisibility); 975 popupWrapper.querySelectorAll(':scope > div').forEach(div => { 976 observer.observe(div, { attributes: true, attributeFilter: ['class'] }); 977 });
978 979 checkPopupVisibility(); 980 981 /// preselect the hotel based on the url 982 if ($(".hotel_list_item.hotel-selected").length > 0) { 983 automaticallySelectedHotel = true; 984 985 $(".hotel_list_item.hotel-selected").trigger("click"); 986 } 987}); 988 989 990 991/// triggered by the book now button on desktop and mobile 992/// similar to ghadashboard, populate the top right form fields and use that logic 993function homePageSearchBookNow() { 994 995 showHideValidation(); 996 997 if (!_jabook_hotelname) { 998 return; 999 } 1000 1001 /// hotel 1002 var selectedHotelValue = _jabook_hotelname == _jabook_allHotelsId ? 1003 _jabook_hotelname : $(".be-property").find("option:contains('" + _jabook_hotelname + "')").val(); 1004 $(".be-property").val(selectedHotelValue).trigger("change"); 1005 1006 /// dates 1007 $(".reservation-inner .txt-checkin").val(_jabook_start_date); 1008 /// manually update the siblings 1009 var mDate = new moment(_jabook_start_date); 1010 var dateString = mDate.format("[<em>]Do MMMM YYYY[</em><small>]dddd[</small>]"); 1011 $(".date-checkin").find(".date-display").html(dateString); 1012 1013 $(".reservation-inner .txt-checkout").val(_jabook_end_date); 1014 mDate = new moment(_jabook_end_date); 1015 dateString = mDate.format("[<em>]Do MMMM YYYY[</em><small>]dddd[</small>]"); 1016 $(".date-checkout").find(".date-display").html(dateString); 1017 1018 // rooms 1019 $(".room-count").val(_jabook_no_of_rooms); 1020 1021 // adults 1022 $(".adults-count").val(_jabook_adult_count).trigger("change"); 1023 1024 // children and infants 1025 var children = _jabook_child_count; 1026 $(".child-count").val(children).trigger("change"); 1027 1028 // promo 1029 $(".reservation-inner .txt-promo").val($("#txtPromoCode").val() || $('#txtPromoCodeMobile').val()); 1030 1031 $("#btnReservationBookNow").click(); 1032} 1033 1034function showHideValidation() { 1035 1036 /// hotel 1037 if (!_jabook_hotelname) { 1038 $(".hotel-selector").addClass("invalid"); 1039 } 1040 else { 1041 $(".hotel-selector").removeClass("invalid"); 1042 } 1043}
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.