https://rutlandhall.co.uk/wp-content/plugins/cn-onejourney/modules…/js/availability-rates.js?ver=0.1
1var OJ = OJ || {}; 2 3OJ.AvailabilityRates = function(id) { 4 this.datepickerConfig = { 5 mode: 'range', 6 inline: true, 7 showMonths: 1, 8 monthSelectorType: 'static', 9 disableMobile: false, 10 minDate: this.getToday() 11 } 12 13 this.connector = new OJ.DataConnector(id) 14 this.displayPrices = true 15 this.displayAvailability = true 16 this.dates = null 17 this.availability = {} 18 this.prePopulate = false 19 20 this.rangeActive = false 21 this.minStay = null 22 this.minStayThreshold = 1 23 24 this.dateSelectionError = false 25} 26 27OJ.AvailabilityRates.prototype.makeDatepicker = function(datepickerElement, datepickerConfig = this.datepickerConfig, tagline = false) { 28 29 // store calendar for use across AvailabilityRates class 30 this.calendar = datepickerElement 31 // assign availablityRates to the calendar for on-the-fly access from elsewhere in the codebase 32 this.calendar.availabilityRates = this 33 34 this.container = this.calendar.closest('form') 35 this.monthRange = datepickerConfig.showMonths || 1 36 37 this.datepickerConfig = this.extendDatepicker(datepickerConfig) 38 39 this.datepicker = flatpickr(datepickerElement, this.datepickerConfig) 40 41 this.dates = this.getMonthRange(datepickerConfig.minDate) 42 43 $(this.container).toggleClass('has-pricing-data', this.displayPrices) 44 45 this.addMonthData() 46 this.populateAvailability(true) 47 48 if(tagline) this.addTagline() 49} 50 51OJ.AvailabilityRates.prototype.populateAvailability = function(reset = false) { 52 53 if(reset && Object.keys(this.availability).length > 0) { 54 this.availability = {} 55 this.datepicker.setDate([]) 56 this.updateDatepicker() 57 } else { 58 let newMonth = this.formatDate(new Date(this.datepicker.currentYear, this.datepicker.currentMonth + (this.monthRange - 1))) 59 if(this.availability[newMonth]) return // we already have data for this month 60 } 61 62 this.connector.getAvailability(this.dates, this.rateId, this.roomId, function(availability){ 63 this.setAvailability(availability) 64 65 if(!availability || availability.message) return false 66 67 if(reset && this.prePopulate) { 68 this.datepicker.setDate(this.getNextAvailableDates(), true) 69 } 70 71 this.updateDatepicker() 72 }.bind(this)) 73} 74 75OJ.AvailabilityRates.prototype.setAvailability = function(availability) { 76 if(!availability) return false 77 78 let message = availability.message 79 80 if(message) { 81 this.displayMessage('\033[31m API Error: ' + message, true) 82 } else { 83 this.availability = Object.assign(this.availability, availability) 84 } 85} 86 87OJ.AvailabilityRates.prototype.extendDatepicker = function(config) { 88 let methods = { 89 onDayCreate: (dateObj, dateStr, fp, dayElem) => this.updateDay(dayElem), 90 onMonthChange: (selectedDates, dateStr, instance) => this.changeMonth(), 91 onValueUpdate: (dateObj, dateStr, fp, dayElem) => this.updateValue(dateStr, dateObj), 92 } 93 94 Object.keys(methods).forEach((method) =>{ 95 if(config[method]) { 96 config[method].push(methods[method]) 97 } else { 98 config[method] = methods[method] 99 } 100 }) 101 102 return { 103 ...config, 104 ...{ 105 showMonths: this.monthRange, 106 minDate: config.minDate ? config.minDate : this.datepickerConfig.minDate 107 } 108 } 109 110} 111 112OJ.AvailabilityRates.prototype.updateDatepicker = function() { 113 this.addMonthData() 114 115 $(this.datepicker.daysContainer).find('.flatpickr-day').each((i, el) => { 116 this.updateDay(el) 117 }) 118} 119 120OJ.AvailabilityRates.prototype.changeMonth = function() { 121 let month = this.datepicker.currentMonth 122 let year = this.datepicker.currentYear 123 124 this.dates = this.getMonthRange(new Date(year, month)) 125 126 this.addMonthData() 127 128 this.populateAvailability() 129} 130 131OJ.AvailabilityRates.prototype.formatDate = function(date) { 132 return flatpickr.formatDate(date, 'Y-m-d') 133} 134 135OJ.AvailabilityRates.prototype.updateDay = function(dayElem) { 136 if(this.dateSelectionError) return 137 138 let dayData = this.displayAvailability ? this.getDayData(dayElem.dateObj) : false 139 let day = $(dayElem).find('.day').length ? $(dayElem).find('.day').text() : $(dayElem).text() 140 let price = dayData ? dayData.price : '' 141 let availability = dayData ? dayData.type : '' // 'available', 'unavailable', 'hotel_closed', 'check_in_closed' 142 let disabled = availability == 'unavailable' || availability == 'hotel_closed' 143 144 if(this.datepicker && this.datepickerConfig.mode == 'range' && this.displayAvailability) disabled = this.checkDisabledState(dayElem, dayData, disabled) 145 146 if($(dayElem).is('.startRange.selected') && disabled){ 147 this.dateSelectionError = true 148 return 149 } 150 151 $(dayElem).html(`<span class="day">${day}</span>`) 152 153 if(this.displayPrices) { 154 $(dayElem).append(`<small class="price">${price}</small>`) 155 } 156 157 if(disabled && !$(dayElem).is('.hidden')) { 158 dayElem.className += ' flatpickr-disabled ' + availability 159 } 160} 161 162OJ.AvailabilityRates.prototype.checkDisabledState = function(dayElem, dayData, disabledState) { 163 let minStay = this.minStay || (dayData?.minimum_stay || 1) 164 165 if(dayElem.dateObj < this.datepickerConfig.minDate) return true 166 167 if(this.datepicker.selectedDates.length == 1 && !this.rangeActive && !$(dayElem).is('.selected')) { 168 169 // disable all dates that precede the start date 170 dayElem.dataset.disabledreason = 'Out of range' 171 dayElem.className += ' outofrange' 172 173 return true 174 } 175 176 if(disabledState == true && this.rangeActive) { 177 178 // if subsequent date is unavailable, the range can go no further 179 this.rangeActive = false 180 181 return false // return enabled state to allow checkout on disabled dates 182 } 183 184 if(this.minStayThreshold > 1) { 185 186 this.minStayThreshold -= 1 187 188 // if subsequent date is below the minimum stay threshold, disable it 189 return true 190 } 191 192 if(minStay > 1 && this.datepicker.selectedDates.length != 1 && !$(dayElem).is('.selected,.inRange') && disabledState == false) { 193 194 let dateStr = this.formatDate(dayElem.dateObj) 195 196 // if there aren't enough nights between date and the next disabled date, these can't be selected 197 let nextDisabledDays = this.getAvailableRange(dateStr) 198 199 if(nextDisabledDays.length > 0 && nextDisabledDays[0] != dateStr) { 200 dayElem.dataset.disabledreason = `${minStay}-night minimum`; 201 return true 202 } 203 204 } 205 206 if($(dayElem).is('.selected.startRange') && this.datepicker.selectedDates.length == 1){ 207 208 // set minimum stay threshold so we can disable subsequent dates accordingly 209 this.minStayThreshold = minStay 210 this.rangeActive = true 211 212 } 213 214 return disabledState 215} 216 217OJ.AvailabilityRates.prototype.getDayData = function(date, range = 1) { 218 return this.availability[(date instanceof Date) ? this.formatDate(date) : date] 219} 220 221OJ.AvailabilityRates.prototype.isAvailable = function(dayData, lastDay) { 222 return dayData.type != 'unavailable' && (dayData.type != 'hotel_closed' || lastDay) 223} 224 225OJ.AvailabilityRates.prototype.getToday = function() { 226 return new Date().fp_incr(0) 227} 228 229OJ.AvailabilityRates.prototype.getAvailableRange = function(dateStr) { 230 // gets first matching date and {range} subsequent dates 231 232 let dates = Object.keys(this.availability) 233 let i = 0 234 let nextavailable = [] 235 let rangeStart = false 236 237 for(let key of dates) { 238 239 if(key == dateStr) rangeStart = true 240 241 if(rangeStart) { 242 let range = this.availability[key].minimum_stay 243 244 nextavailable = dates.slice(i, i + (range + 1)).filter((date, sliceIndex) => { 245 return this.isAvailable(this.availability[date], sliceIndex > 1 && sliceIndex == range) 246 }) 247 248 if(nextavailable.length != (range + 1)) { 249 i++ 250 continue 251 } else { 252 break 253 } 254 } 255 256 i++ 257 } 258 259 return nextavailable 260 261} 262 263OJ.AvailabilityRates.prototype.removeDates = function(reselect) { 264 this.minStayThreshold = 1 265 this.rangeActive = false 266
267 let currentMonth = this.datepicker.currentMonth 268 269 if(this.dateSelectionError) { 270 this.dateSelectionError = false 271 reselect = true 272 } 273 274 this.datepicker.setDate(reselect ? this.getNextAvailableDates() : [], reselect) 275 276 if(!reselect) { 277 this.datepicker.changeMonth(currentMonth, false); 278 } 279 280 this.updateDatepicker() 281} 282 283OJ.AvailabilityRates.prototype.updateValue = function(dateStr, dateObj) { 284 this.checkDayForMessage(dateStr) 285 this.addMonthData() 286 287 if(dateObj[1] && dateStr == this.formatDate(dateObj[1]) || this.dateSelectionError){ 288 this.removeDates() 289 } if(this.datepicker.selectedDates.length == 2 && this.datepickerConfig.mode == 'range') { 290 this.rangeActive = false 291 } 292} 293 294OJ.AvailabilityRates.prototype.getMonthRange = function(date) { 295 let month = date.getMonth() 296 let year = date.getFullYear() 297 298 return [ 299 this.formatDate(new Date(year, month, 1) < new Date() ? new Date() : new Date(year, month, 1)), 300 this.formatDate(new Date(year, month + parseInt(this.monthRange), 0)) 301 ] 302} 303 304OJ.AvailabilityRates.prototype.addMonthData = function() { 305 $(this.datepicker.daysContainer).children().each((i, el) => { 306 el.dataset.month = flatpickr.formatDate(new Date(this.datepicker.currentYear, this.datepicker.currentMonth + i), 'M Y') 307 }) 308} 309 310OJ.AvailabilityRates.prototype.setMinDate = function(offset) { 311 let today = this.getToday() 312 return this.datepickerConfig.minDate = today.fp_incr(offset) 313} 314 315OJ.AvailabilityRates.prototype.setMinStay = function(minStay) { 316 return this.minStay = minStay 317} 318 319OJ.AvailabilityRates.prototype.getNextAvailableDates = function() { 320 321 if(Object.keys(this.availability).length) { 322 323 let firstAvailable = this.getAvailableRange(this.formatDate(this.datepickerConfig.minDate)) 324 325 if(firstAvailable.length != 0) { 326 return [firstAvailable[0], firstAvailable[firstAvailable.length - 1]] 327 } else { 328 return [] 329 } 330 331 } else { 332 let startDate = this.datepickerConfig.minDate 333 return [startDate, startDate.fp_incr(1)] 334 } 335} 336 337OJ.AvailabilityRates.prototype.checkDayForMessage = function(dateStr) { 338 if(this.datepicker.selectedDates.length == 1){ 339 this.removeMessages() 340 } 341 342 let dayData = this.displayAvailability ? this.getDayData(dateStr) : false 343 344 if(!dayData) return false 345 346 if(dayData.type == 'check_in_closed') { 347 this.displayMessage("No check-in allowed on selected date.") 348 } 349 350 let minStay = this.minStay || (dayData?.minimum_stay || 1) 351 352 if(minStay > 1) { 353 354 let message = `${minStay}-Night Minimum Stay`; 355 356 if(this.displayPrices) message = `${dayData.price} | ${message}`; 357 358 this.displayMessage(message) 359 } 360} 361 362OJ.AvailabilityRates.prototype.displayMessage = function(message, consoleMessage) { 363 if(!consoleMessage) { 364 this.removeMessages() 365 366 $(`<div class="c-datepicker-message js-booking-data-message"><p>${message}</p></div>`).appendTo($(this.datepicker.calendarContainer)) 367 } else { 368 console.log(message); 369 } 370} 371 372OJ.AvailabilityRates.prototype.removeMessages = function() { 373 $('.js-booking-data-message').remove() 374} 375 376OJ.AvailabilityRates.prototype.togglePrices = function(toggle) { 377 if(ojAvailabilityRates.showPrices !== 'true') return 378 379 $(this.container).toggleClass('has-pricing-data', toggle) 380 381 if(this.displayPrices != toggle) { 382 this.displayPrices = toggle 383 this.updateDatepicker() 384 } 385} 386 387OJ.AvailabilityRates.prototype.setDisplayPrices = function(displayPrices) { 388 this.displayPrices = displayPrices 389} 390 391OJ.AvailabilityRates.prototype.toggleAvailability = function(toggle) { 392 if(this.displayAvailability != toggle) { 393 this.displayAvailability = toggle 394 this.updateDatepicker() 395 } 396} 397 398OJ.AvailabilityRates.prototype.setDisplayAvailability = function(displayAvailability) { 399 this.displayAvailability = displayAvailability 400} 401 402OJ.AvailabilityRates.prototype.setRate = function(rateId, refresh) { 403 let newRate = this.rateId != rateId 404 this.rateId = rateId 405 406 if(refresh && newRate) { 407 this.populateAvailability(true) 408 } 409} 410 411OJ.AvailabilityRates.prototype.setRoom = function(roomId, refresh) { 412 let newRoomID = this.roomId != roomId 413 this.roomId = roomId 414 415 if(refresh && newRoomID) { 416 this.populateAvailability(true) 417 } 418} 419 420OJ.AvailabilityRates.prototype.addTagline = function() { 421 if($(this.container).find('.onejourney-tagline').length) return 422
423 let container = this.container 424 425 $.get("/wp-content/plugins/cn-onejourney/assets/powered-by.svg", function(svg) { 426 $(container).append(` 427 <a href='//onejourney.travel' target='_blank' class='onejourney-tagline'> 428 ${$(svg).find('svg')[0].outerHTML} 429 </a> 430 `) 431 }) 432} 433 434function populateDatepickers() { 435 $('[data-module="datepicker-booking-form"]').each(function(i, el) { 436 let moduleOptions = $(el).data('module-options') 437 let datepicker = $(el).find('.js-booking-form-datepicker')[0] 438 439 if(!moduleOptions) return 440 441 let availabilityRates = new OJ.AvailabilityRates() 442 443 if(ojAvailabilityRates.enabled === 'true') { 444 let config = Object.assign({}, datepicker._flatpickr.config) 445 446 config['minDate'] = availabilityRates.setMinDate(moduleOptions.minimumAdvanceReservation || 0) 447 448 availabilityRates.prePopulate = true 449 availabilityRates.setDisplayPrices(ojAvailabilityRates.showPrices === 'true') 450 availabilityRates.makeDatepicker(datepicker, config, true) 451 } 452 453 }) 454} 455 456$(populateDatepickers)
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.