PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.8.16
VikBooking Hotel Booking Engine & PMS v1.8.16
1.8.16 1.8.15 1.8.14 1.8.13 1.8.12 1.8.11 1.8.10 1.8.9 1.8.6 1.8.7 1.8.8 trunk 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 All 37 releases
vikbooking / site / views / roomdetails / tmpl / default.php

default.php in VikBooking Hotel Booking Engine & PMS 1.8.16, at site/views/roomdetails/tmpl/default.php

806 lines 25.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package VikBooking
4 * @subpackage com_vikbooking
5 * @author Alessio Gaggii - E4J srl
6 * @copyright Copyright (C) 2025 e4j - E4J srl. All rights reserved.
7 * @license GNU General Public License version 2 or later; see LICENSE
8 * @link https://vikwp.com
9 */
10
11 defined('ABSPATH') or die('No script kiddies please!');
12
13 $vbo_app = VikBooking::getVboApplication();
14 $vbo_app->loadDatePicker(['type' => 'dates_range']);
15
16 // register lang vars for JS
17 JText::script('VBODISTFEATURERUNIT');
18 JText::script('VBO_GEO_ADDRESS');
19 JText::script('VBSELPRDATE');
20
21 $is_mobile = VikBooking::detectUserAgent(false, false);
22
23 $def_nights_cal = VikBooking::getDefaultNightsCalendar();
24 $vbdateformat = VikBooking::getDateFormat();
25 $datesep = VikBooking::getDateSeparator();
26 // datepicker calendars
27 if ($vbdateformat == "%d/%m/%Y") {
28 $juidf = 'dd/mm/yy';
29 } elseif ($vbdateformat == "%m/%d/%Y") {
30 $juidf = 'mm/dd/yy';
31 } else {
32 $juidf = 'yy/mm/dd';
33 }
34
35 // JSON-decode room parameters
36 $rparams = json_decode($this->room['params'], true);
37
38 // room layout name
39 $layout = VikBooking::getRoomParam('layout_style', $rparams, 'classic');
40
41 $min_days_advance = VikBooking::getMinDaysAdvance();
42 $max_date_future = VikBooking::getMaxDateFuture($this->room['id']);
43
44 // load assets
45 $document = JFactory::getDocument();
46 $document->addStyleSheet(VBO_SITE_URI.'resources/jquery.fancybox.css');
47 JHtml::fetch('script', VBO_SITE_URI.'resources/jquery.fancybox.js');
48 $navdecl = '
49 jQuery(function() {
50 jQuery(".vbomodalframe").fancybox({
51 "helpers": {
52 "overlay": {
53 "locked": false
54 }
55 },
56 "width": "75%",
57 "height": "75%",
58 "autoScale": false,
59 "transitionIn": "none",
60 "transitionOut": "none",
61 "padding": 0,
62 "type": "iframe"
63 });
64 });';
65 $document->addScriptDeclaration($navdecl);
66 $document->addStyleSheet(VBO_SITE_URI.'resources/vikfxgallery.css');
67 JHtml::fetch('script', VBO_SITE_URI.'resources/vikfxgallery.js');
68
69 // photo gallery script declaration
70 if (!empty($this->room['moreimgs'])) {
71 $vikfx = '
72 jQuery(function() {
73 window["vikfxgallery"] = jQuery(".vikfx-gallery a").vikFxGallery();
74 jQuery(".vikfx-gallery-previous-image, .vikfx-gallery-next-image, .vikfx-gallery-open").click(function() {
75 if (typeof window["vikfxgallery"] !== "undefined") {
76 window["vikfxgallery"].open();
77 }
78 });
79 });';
80 $document->addScriptDeclaration($vikfx);
81 }
82
83 // set up script declarations for datepicker
84 $declarations = [];
85
86 // helper functions
87 $declarations[] = <<<JAVASCRIPT
88 jQuery.noConflict();
89
90 function vbGetDateObject(dstring) {
91 var dparts = dstring.split("-");
92 return new Date(dparts[0], (parseInt(dparts[1]) - 1), parseInt(dparts[2]), 0, 0, 0, 0);
93 }
94
95 function vbFullObject(obj) {
96 var jk;
97 for (jk in obj) {
98 return obj.hasOwnProperty(jk);
99 }
100 }
101
102 var vbrestrctarange, vbrestrctdrange, vbrestrcta, vbrestrctd;
103
104 JAVASCRIPT;
105
106 /**
107 * We need to exclude from the datepicker calendars all fully booked dates.
108 * For this reason we loop for 18 months in the future for the sole purpose
109 * of pushing other dates onto $push_disabled_in/out.
110 */
111 $push_disabled_in = [];
112 $push_disabled_out = [];
113 $inonout_allowed = true;
114 $timeopst = VikBooking::getTimeOpenStore();
115 if (is_array($timeopst)) {
116 if ($timeopst[0] < $timeopst[1]) {
117 // check-in not allowed on a day where there is already a check out (no arrivals/depatures on the same day)
118 $inonout_allowed = false;
119 }
120 }
121 if (!empty($this->busy)) {
122 // start date from today
123 $now_info = getdate();
124 // we loop for the next 18 months ahead to disable dates for check-in/check-out
125 $max_ts = mktime(23, 59, 59, $now_info['mon'] + 18, $now_info['mday'], $now_info['year']);
126 // loop until the maximum date in the future
127 $wasprevbusy = false;
128 while ($now_info[0] < $max_ts) {
129 $totfound = 0;
130 $ischeckinday = false;
131 $ischeckoutday = false;
132 foreach ($this->busy as $b) {
133 $info_in = getdate($b['checkin']);
134 $checkin_ts = mktime(0, 0, 0, $info_in['mon'], $info_in['mday'], $info_in['year']);
135 $info_out = getdate($b['checkout']);
136 $checkout_ts = mktime(0, 0, 0, $info_out['mon'], $info_out['mday'], $info_out['year']);
137 if ($now_info[0] >= $checkin_ts && $now_info[0] == $checkout_ts) {
138 $ischeckoutday = true;
139 }
140 if ($now_info[0] >= $checkin_ts && $now_info[0] < $checkout_ts) {
141 $totfound++;
142 if ($now_info[0] == $checkin_ts) {
143 $ischeckinday = true;
144 }
145 }
146 }
147 if ($totfound >= $this->room['units']) {
148 $push_disabled_in[] = date('Y-m-d', $now_info[0]);
149 if (!$ischeckinday || $wasprevbusy) {
150 $push_disabled_out[] = date('Y-m-d', $now_info[0]);
151 } elseif ($ischeckinday && !$inonout_allowed && !$wasprevbusy) {
152 // check-out not allowed on a day where someone is already checking-in
153 $push_disabled_out[] = date('Y-m-d', $now_info[0]);
154 }
155 // update previous day status only after checking the disabled out date
156 $wasprevbusy = true;
157 } else {
158 // update flag
159 $wasprevbusy = false;
160 if (!$totfound && $ischeckoutday && !$inonout_allowed && !($this->room['units'] > 1)) {
161 $push_disabled_in[] = date('Y-m-d', $now_info[0]);
162 }
163 }
164 // go to next day
165 $now_info = getdate(mktime(0, 0, 0, $now_info['mon'], ($now_info['mday'] + 1), $now_info['year']));
166 }
167 }
168
169 // room-level restrictions
170 $restrictions = VikBooking::loadRestrictions(true, [$this->room['id']]);
171
172 // restrictions
173 $totrestrictions = count($restrictions);
174 $wdaysrestrictions = [];
175 $wdaystworestrictions = [];
176 $wdaysrestrictionsrange = [];
177 $wdaysrestrictionsmonths = [];
178 $ctarestrictionsrange = [];
179 $ctarestrictionsmonths = [];
180 $ctdrestrictionsrange = [];
181 $ctdrestrictionsmonths = [];
182 $monthscomborestr = [];
183 $minlosrestrictions = [];
184 $minlosrestrictionsrange = [];
185 $maxlosrestrictions = [];
186 $maxlosrestrictionsrange = [];
187 $notmultiplyminlosrestrictions = [];
188
189 if ($totrestrictions > 0) {
190 foreach ($restrictions as $rmonth => $restr) {
191 if ($rmonth != 'range') {
192 if (strlen((string)$restr['wday'])) {
193 $wdaysrestrictions[($rmonth - 1)] = $restr['wday'];
194 $wdaysrestrictionsmonths[] = $rmonth;
195 if (strlen((string)$restr['wdaytwo'])) {
196 $wdaystworestrictions[($rmonth - 1)] = $restr['wdaytwo'];
197 $monthscomborestr[($rmonth - 1)] = VikBooking::parseJsDrangeWdayCombo($restr);
198 }
199 } elseif (!empty($restr['ctad']) || !empty($restr['ctdd'])) {
200 if (!empty($restr['ctad'])) {
201 $ctarestrictionsmonths[($rmonth - 1)] = explode(',', $restr['ctad']);
202 }
203 if (!empty($restr['ctdd'])) {
204 $ctdrestrictionsmonths[($rmonth - 1)] = explode(',', $restr['ctdd']);
205 }
206 }
207 if ($restr['multiplyminlos'] == 0) {
208 $notmultiplyminlosrestrictions[] = $rmonth;
209 }
210 $minlosrestrictions[($rmonth - 1)] = $restr['minlos'];
211 if (!empty($restr['maxlos']) && $restr['maxlos'] > 0 && $restr['maxlos'] >= $restr['minlos']) {
212 $maxlosrestrictions[($rmonth - 1)] = $restr['maxlos'];
213 }
214 } else {
215 foreach ($restr as $kr => $drestr) {
216 if (strlen((string)$drestr['wday'])) {
217 $wdaysrestrictionsrange[$kr][0] = date('Y-m-d', $drestr['dfrom']);
218 $wdaysrestrictionsrange[$kr][1] = date('Y-m-d', $drestr['dto']);
219 $wdaysrestrictionsrange[$kr][2] = $drestr['wday'];
220 $wdaysrestrictionsrange[$kr][3] = $drestr['multiplyminlos'];
221 $wdaysrestrictionsrange[$kr][4] = strlen((string)$drestr['wdaytwo']) ? $drestr['wdaytwo'] : -1;
222 $wdaysrestrictionsrange[$kr][5] = VikBooking::parseJsDrangeWdayCombo($drestr);
223 } elseif (!empty($drestr['ctad']) || !empty($drestr['ctdd'])) {
224 $ctfrom = date('Y-m-d', $drestr['dfrom']);
225 $ctto = date('Y-m-d', $drestr['dto']);
226 if (!empty($drestr['ctad'])) {
227 $ctarestrictionsrange[$kr][0] = $ctfrom;
228 $ctarestrictionsrange[$kr][1] = $ctto;
229 $ctarestrictionsrange[$kr][2] = explode(',', $drestr['ctad']);
230 }
231 if (!empty($drestr['ctdd'])) {
232 $ctdrestrictionsrange[$kr][0] = $ctfrom;
233 $ctdrestrictionsrange[$kr][1] = $ctto;
234 $ctdrestrictionsrange[$kr][2] = explode(',', $drestr['ctdd']);
235 }
236 }
237 $minlosrestrictionsrange[$kr][0] = date('Y-m-d', $drestr['dfrom']);
238 $minlosrestrictionsrange[$kr][1] = date('Y-m-d', $drestr['dto']);
239 $minlosrestrictionsrange[$kr][2] = $drestr['minlos'];
240 if (!empty($drestr['maxlos']) && $drestr['maxlos'] > 0 && $drestr['maxlos'] >= $drestr['minlos']) {
241 $maxlosrestrictionsrange[$kr] = $drestr['maxlos'];
242 }
243 }
244 unset($restrictions['range']);
245 }
246 }
247
248 // prepare JSON-encoded values
249 $json_vals = [
250 'vbrestrmonthswdays' => json_encode($wdaysrestrictionsmonths),
251 'vbrestrmonths' => json_encode(array_keys($restrictions)),
252 'vbrestrmonthscombojn' => json_encode($monthscomborestr),
253 'vbrestrminlos' => json_encode((object) $minlosrestrictions),
254 'vbrestrminlosrangejn' => json_encode($minlosrestrictionsrange),
255 'vbrestrmultiplyminlos' => json_encode($notmultiplyminlosrestrictions),
256 'vbrestrmaxlos' => json_encode((object) $maxlosrestrictions),
257 'vbrestrmaxlosrangejn' => json_encode($maxlosrestrictionsrange),
258 'vbrestrwdaysrangejn' => json_encode($wdaysrestrictionsrange),
259 'vbrestrcta' => json_encode($ctarestrictionsmonths),
260 'vbrestrctarange' => json_encode($ctarestrictionsrange),
261 'vbrestrctd' => json_encode($ctdrestrictionsmonths),
262 'vbrestrctdrange' => json_encode($ctdrestrictionsrange),
263 ];
264
265 // start restrictions declaration
266 $resdecl = <<<JAVASCRIPT
267 var vbrestrmonthswdays = {$json_vals['vbrestrmonthswdays']};
268 var vbrestrmonths = {$json_vals['vbrestrmonths']};
269 var vbrestrmonthscombojn = {$json_vals['vbrestrmonthscombojn']};
270 var vbrestrminlos = {$json_vals['vbrestrminlos']};
271 var vbrestrminlosrangejn = {$json_vals['vbrestrminlosrangejn']};
272 var vbrestrmultiplyminlos = {$json_vals['vbrestrmultiplyminlos']};
273 var vbrestrmaxlos = {$json_vals['vbrestrmaxlos']};
274 var vbrestrmaxlosrangejn = {$json_vals['vbrestrmaxlosrangejn']};
275 var vbrestrwdaysrangejn = {$json_vals['vbrestrwdaysrangejn']};
276 var vbrestrcta = {$json_vals['vbrestrcta']};
277 var vbrestrctarange = {$json_vals['vbrestrctarange']};
278 var vbrestrctd = {$json_vals['vbrestrctd']};
279 var vbrestrctdrange = {$json_vals['vbrestrctdrange']};
280 var vbcombowdays = {};
281
282 function vbRefreshCheckout(darrive) {
283 if (vbFullObject(vbcombowdays)) {
284 var vbtosort = new Array();
285 for (var vbi in vbcombowdays) {
286 if (vbcombowdays.hasOwnProperty(vbi)) {
287 var vbusedate = darrive;
288 vbtosort[vbi] = vbusedate.setDate(vbusedate.getDate() + (vbcombowdays[vbi] - 1 - vbusedate.getDay() + 7) % 7 + 1);
289 }
290 }
291 vbtosort.sort(function(da, db) {
292 return da > db ? 1 : -1;
293 });
294 for (var vbnext in vbtosort) {
295 if (vbtosort.hasOwnProperty(vbnext)) {
296 var vbfirstnextd = new Date(vbtosort[vbnext]);
297 jQuery('#checkindate').vboDatesRangePicker('checkout', 'minDate', vbfirstnextd);
298 jQuery('#checkindate').vboDatesRangePicker('checkout', 'setcheckoutdate', vbfirstnextd);
299 break;
300 }
301 }
302 }
303 }
304
305 function vbSetMinCheckoutDate(selectedDate) {
306 var minlos = {$def_nights_cal};
307 var maxlosrange = 0;
308 var nowcheckin = jQuery('#checkindate').vboDatesRangePicker('getCheckinDate');
309 var nowd = nowcheckin.getDay();
310 var nowcheckindate = new Date(nowcheckin.getTime());
311 vbcombowdays = {};
312 if (vbFullObject(vbrestrminlosrangejn)) {
313 for (var rk in vbrestrminlosrangejn) {
314 if (vbrestrminlosrangejn.hasOwnProperty(rk)) {
315 var minldrangeinit = vbGetDateObject(vbrestrminlosrangejn[rk][0]);
316 if (nowcheckindate >= minldrangeinit) {
317 var minldrangeend = vbGetDateObject(vbrestrminlosrangejn[rk][1]);
318 if (nowcheckindate <= minldrangeend) {
319 minlos = parseInt(vbrestrminlosrangejn[rk][2]);
320 if (vbFullObject(vbrestrmaxlosrangejn)) {
321 if (rk in vbrestrmaxlosrangejn) {
322 maxlosrange = parseInt(vbrestrmaxlosrangejn[rk]);
323 }
324 }
325 if (rk in vbrestrwdaysrangejn && nowd in vbrestrwdaysrangejn[rk][5]) {
326 vbcombowdays = vbrestrwdaysrangejn[rk][5][nowd];
327 }
328 }
329 }
330 }
331 }
332 }
333 var nowm = nowcheckin.getMonth();
334 if (vbFullObject(vbrestrmonthscombojn) && vbrestrmonthscombojn.hasOwnProperty(nowm)) {
335 if (nowd in vbrestrmonthscombojn[nowm]) {
336 vbcombowdays = vbrestrmonthscombojn[nowm][nowd];
337 }
338 }
339 if (vbrestrmonths.includes((nowm + 1))) {
340 minlos = parseInt(vbrestrminlos[nowm]);
341 }
342 nowcheckindate.setDate(nowcheckindate.getDate() + minlos);
343 jQuery('#checkindate').vboDatesRangePicker('checkout', 'minDate', nowcheckindate);
344 jQuery('#checkindate').vboDatesRangePicker('checkout', 'minStayNights', minlos);
345 if (maxlosrange > 0) {
346 var diffmaxminlos = maxlosrange - minlos;
347 var maxcheckoutdate = new Date(nowcheckindate.getTime());
348 maxcheckoutdate.setDate(maxcheckoutdate.getDate() + diffmaxminlos);
349 jQuery('#checkindate').vboDatesRangePicker('checkout', 'maxDate', maxcheckoutdate);
350 }
351 if (nowm in vbrestrmaxlos) {
352 var diffmaxminlos = parseInt(vbrestrmaxlos[nowm]) - minlos;
353 var maxcheckoutdate = new Date(nowcheckindate.getTime());
354 maxcheckoutdate.setDate(maxcheckoutdate.getDate() + diffmaxminlos);
355 jQuery('#checkindate').vboDatesRangePicker('checkout', 'maxDate', maxcheckoutdate);
356 }
357 if (!vbFullObject(vbcombowdays)) {
358 var is_checkout_disabled = false;
359 if (typeof selectedDate !== 'undefined' && typeof jQuery('#checkindate').vboDatesRangePicker('drpoption', 'beforeShowDay.checkout') === 'function') {
360 // let the datepicker validate if the min date to set for check-out is disabled due to CTD rules
361 is_checkout_disabled = !jQuery('#checkindate').vboDatesRangePicker('drpoption', 'beforeShowDay.checkout')(nowcheckindate)[0];
362 }
363 if (!is_checkout_disabled) {
364 jQuery('#checkindate').vboDatesRangePicker('checkout', 'setCheckoutDate', nowcheckindate);
365 } else {
366 setTimeout(() => {
367 // make sure the minimum date just set for the checkout has not populated a CTD date that we do not want
368 var current_out_dt = jQuery('#checkindate').vboDatesRangePicker('getCheckoutDate');
369 if (current_out_dt && current_out_dt.getTime() === nowcheckindate.getTime()) {
370 jQuery('#checkindate').vboDatesRangePicker('checkout', 'setCheckoutDate', null);
371 }
372 }, 100);
373 }
374 } else {
375 vbRefreshCheckout(nowcheckin);
376 }
377 }
378 JAVASCRIPT;
379
380 if ($wdaysrestrictions || $wdaysrestrictionsrange) {
381 $dfull_in = '';
382 $dfull_out = '';
383
384 if ($push_disabled_in) {
385 $dfull_in = <<<JAVASCRIPT
386 var actd = jQuery.datepicker.formatDate('yy-mm-dd', date);
387 if (vbfulldays_in.includes(actd)) {
388 return [false];
389 }
390 JAVASCRIPT;
391 }
392
393 if ($push_disabled_out) {
394 $dfull_out = <<<JAVASCRIPT
395 var actd = jQuery.datepicker.formatDate('yy-mm-dd', date);
396 if (vbfulldays_out.includes(actd)) {
397 return [false];
398 }
399 // exclude days after a fully booked day, because a date selection cannot contain a fully booked day in between.
400 var exclude_after = false;
401 var last_fully_booked = null;
402 var nowcheckin = jQuery('#checkindate').vboDatesRangePicker('getCheckinDate');
403 if (nowcheckin && vbfulldays_out.length) {
404 var nowcheckindate = new Date(nowcheckin.getTime());
405 nowcheckindate.setHours(0);
406 nowcheckindate.setMinutes(0);
407 nowcheckindate.setSeconds(0);
408 nowcheckindate.setMilliseconds(0);
409 for (var i in vbfulldays_out) {
410 var nowfullday = new Date(vbfulldays_out[i]);
411 nowfullday.setHours(0);
412 nowfullday.setMinutes(0);
413 nowfullday.setSeconds(0);
414 nowfullday.setMilliseconds(0);
415 exclude_after = (nowcheckindate <= nowfullday);
416 if (exclude_after) {
417 // selected check-in date is before a fully booked day
418 last_fully_booked = nowfullday;
419 break;
420 }
421 }
422 }
423 if (exclude_after) {
424 date.setHours(0);
425 date.setMinutes(0);
426 date.setSeconds(0);
427 date.setMilliseconds(0);
428 if (date > last_fully_booked) {
429 // current day for display is after a fully booked day, with a selected check-in day before a fully booked day. Disable it.
430 return [false];
431 }
432 }
433 JAVASCRIPT;
434 }
435
436 // prepare JSON-encoded values
437 $json_vals = [
438 'vbrestrwdays' => json_encode((object) $wdaysrestrictions),
439 'vbrestrwdaystwo' => json_encode((object) $wdaystworestrictions),
440 'vbfulldays_in' => json_encode($push_disabled_in),
441 'vbfulldays_out' => json_encode($push_disabled_out),
442 ];
443
444 // finalize restrictions declaration
445 $resdecl .= <<<JAVASCRIPT
446 var vbrestrwdays = {$json_vals['vbrestrwdays']};
447 var vbrestrwdaystwo = {$json_vals['vbrestrwdaystwo']};
448 var vbfulldays_in = {$json_vals['vbfulldays_in']};
449 var vbfulldays_out = {$json_vals['vbfulldays_out']};
450
451 function vbIsDayDisabled(date) {
452 if (!vbIsDayOpen(date) || !vboValidateCta(date)) {
453 return [false];
454 }
455 var m = date.getMonth(), wd = date.getDay();
456 if (vbFullObject(vbrestrwdaysrangejn)) {
457 for (var rk in vbrestrwdaysrangejn) {
458 if (vbrestrwdaysrangejn.hasOwnProperty(rk)) {
459 var wdrangeinit = vbGetDateObject(vbrestrwdaysrangejn[rk][0]);
460 if (date >= wdrangeinit) {
461 var wdrangeend = vbGetDateObject(vbrestrwdaysrangejn[rk][1]);
462 if (date <= wdrangeend) {
463 if (wd != vbrestrwdaysrangejn[rk][2]) {
464 if (vbrestrwdaysrangejn[rk][4] == -1 || wd != vbrestrwdaysrangejn[rk][4]) {
465 return [false];
466 }
467 }
468 }
469 }
470 }
471 }
472 }
473
474 {$dfull_in}
475
476 if (vbFullObject(vbrestrwdays)) {
477 if (!vbrestrmonthswdays.includes((m+1))) {
478 return [true];
479 }
480 if (wd == vbrestrwdays[m]) {
481 return [true];
482 }
483 if (vbFullObject(vbrestrwdaystwo)) {
484 if (wd == vbrestrwdaystwo[m]) {
485 return [true];
486 }
487 }
488 return [false];
489 }
490 return [true];
491 }
492
493 function vbIsDayDisabledCheckout(date) {
494 if (!vbIsDayOpen(date) || !vboValidateCtd(date)) {
495 return [false];
496 }
497 var m = date.getMonth(), wd = date.getDay();
498
499 {$dfull_out}
500
501 if (vbFullObject(vbcombowdays)) {
502 if (vbcombowdays.includes(wd)) {
503 return [true];
504 } else {
505 return [false];
506 }
507 }
508 if (vbFullObject(vbrestrwdaysrangejn)) {
509 for (var rk in vbrestrwdaysrangejn) {
510 if (vbrestrwdaysrangejn.hasOwnProperty(rk)) {
511 var wdrangeinit = vbGetDateObject(vbrestrwdaysrangejn[rk][0]);
512 if (date >= wdrangeinit) {
513 var wdrangeend = vbGetDateObject(vbrestrwdaysrangejn[rk][1]);
514 if (date <= wdrangeend) {
515 if (wd != vbrestrwdaysrangejn[rk][2] && vbrestrwdaysrangejn[rk][3] == 1) {
516 return [false];
517 }
518 }
519 }
520 }
521 }
522 }
523 if (vbFullObject(vbrestrwdays)) {
524 if (!vbrestrmonthswdays.includes((m+1)) || vbrestrmultiplyminlos.includes((m+1))) {
525 return [true];
526 }
527 if (wd == vbrestrwdays[m]) {
528 return [true];
529 }
530 return [false];
531 }
532 return [true];
533 }
534 JAVASCRIPT;
535 }
536
537 // push restrictions JS declaration
538 $declarations[] = $resdecl;
539 }
540
541 // fully booked dates
542 if ($push_disabled_in) {
543 // prepare JSON-encoded values
544 $json_vals = [
545 'vbfulldays_in' => json_encode($push_disabled_in),
546 ];
547
548 // push JS declaration
549 $declarations[] = <<<JAVASCRIPT
550 var vbfulldays_in = {$json_vals['vbfulldays_in']};
551 function vbIsDayFull(date) {
552 if (!vbIsDayOpen(date) || !vboValidateCta(date)) {
553 return [false];
554 }
555 var actd = jQuery.datepicker.formatDate('yy-mm-dd', date);
556 if (!vbfulldays_in.includes(actd)) {
557 return [true];
558 }
559 return [false];
560 }
561 JAVASCRIPT;
562 }
563
564 if ($push_disabled_out) {
565 // prepare JSON-encoded values
566 $json_vals = [
567 'vbfulldays_out' => json_encode($push_disabled_out),
568 ];
569
570 // push JS declaration
571 $declarations[] = <<<JAVASCRIPT
572 var vbfulldays_out = {$json_vals['vbfulldays_out']};
573 function vbIsDayFullOut(date) {
574 if (!vbIsDayOpen(date) || !vboValidateCtd(date)) {
575 return [false];
576 }
577 var actd = jQuery.datepicker.formatDate('yy-mm-dd', date);
578 if (!vbfulldays_out.includes(actd)) {
579 // exclude days after a fully booked day, because a date selection cannot contain a fully booked day in between.
580 var exclude_after = false;
581 var last_fully_booked = null;
582 var nowcheckin = jQuery('#checkindate').vboDatesRangePicker('getCheckinDate');
583 if (nowcheckin && vbfulldays_out.length) {
584 var nowcheckindate = new Date(nowcheckin.getTime());
585 nowcheckindate.setHours(0);
586 nowcheckindate.setMinutes(0);
587 nowcheckindate.setSeconds(0);
588 nowcheckindate.setMilliseconds(0);
589 for (var i in vbfulldays_out) {
590 var nowfullday = new Date(vbfulldays_out[i]);
591 nowfullday.setHours(0);
592 nowfullday.setMinutes(0);
593 nowfullday.setSeconds(0);
594 nowfullday.setMilliseconds(0);
595 exclude_after = (nowcheckindate <= nowfullday);
596 if (exclude_after) {
597 // selected check-in date is before a fully booked day
598 last_fully_booked = nowfullday;
599 break;
600 }
601 }
602 }
603 if (exclude_after) {
604 date.setHours(0);
605 date.setMinutes(0);
606 date.setSeconds(0);
607 date.setMilliseconds(0);
608 if (date > last_fully_booked) {
609 // current day for display is after a fully booked day, with a selected check-in day before a fully booked day. Disable it.
610 return [false];
611 }
612 }
613 return [true];
614 }
615 return [false];
616 }
617 JAVASCRIPT;
618 }
619
620 // prepare JSON-encoded values
621 $closing_dates = VikBooking::parseJsClosingDates();
622 $json_vals = [
623 'vbclosingdates' => json_encode($closing_dates),
624 ];
625
626 // dates validation
627 $dtdecl = <<<JAVASCRIPT
628 var vbclosingdates = {$json_vals['vbclosingdates']};
629
630 function vbCheckClosingDates(date) {
631 if (!vbIsDayOpen(date)) {
632 return [false];
633 }
634 return [true];
635 }
636
637 function vbIsDayOpen(date) {
638 if (vbFullObject(vbclosingdates)) {
639 for (var cd in vbclosingdates) {
640 if (vbclosingdates.hasOwnProperty(cd)) {
641 var cdfrom = vbGetDateObject(vbclosingdates[cd][0]);
642 var cdto = vbGetDateObject(vbclosingdates[cd][1]);
643 if (date >= cdfrom && date <= cdto) {
644 return false;
645 }
646 }
647 }
648 }
649 return true;
650 }
651
652 function vboCheckClosingDatesIn(date) {
653 var isdayopen = vbIsDayOpen(date) && vboValidateCta(date);
654 return [isdayopen];
655 }
656
657 function vboCheckClosingDatesOut(date) {
658 var isdayopen = vbIsDayOpen(date) && vboValidateCtd(date);
659 return [isdayopen];
660 }
661
662 function vboValidateCta(date) {
663 var m = date.getMonth(), wd = date.getDay();
664 if (vbFullObject(vbrestrctarange)) {
665 for (var rk in vbrestrctarange) {
666 if (vbrestrctarange.hasOwnProperty(rk)) {
667 var wdrangeinit = vbGetDateObject(vbrestrctarange[rk][0]);
668 if (date >= wdrangeinit) {
669 var wdrangeend = vbGetDateObject(vbrestrctarange[rk][1]);
670 if (date <= wdrangeend) {
671 if (vbrestrctarange[rk][2].includes('-'+wd+'-')) {
672 return false;
673 }
674 }
675 }
676 }
677 }
678 }
679 if (vbFullObject(vbrestrcta)) {
680 if (vbrestrcta.hasOwnProperty(m) && vbrestrcta[m].includes('-'+wd+'-')) {
681 return false;
682 }
683 }
684 return true;
685 }
686
687 function vboValidateCtd(date) {
688 var m = date.getMonth(), wd = date.getDay();
689 if (vbFullObject(vbrestrctdrange)) {
690 for (var rk in vbrestrctdrange) {
691 if (vbrestrctdrange.hasOwnProperty(rk)) {
692 var wdrangeinit = vbGetDateObject(vbrestrctdrange[rk][0]);
693 if (date >= wdrangeinit) {
694 var wdrangeend = vbGetDateObject(vbrestrctdrange[rk][1]);
695 if (date <= wdrangeend) {
696 if (vbrestrctdrange[rk][2].includes('-'+wd+'-')) {
697 return false;
698 }
699 }
700 }
701 }
702 }
703 }
704 if (vbFullObject(vbrestrctd)) {
705 if (vbrestrctd.hasOwnProperty(m) && vbrestrctd[m].includes('-'+wd+'-')) {
706 return false;
707 }
708 }
709 return true;
710 }
711
712 function vbSetGlobalMinCheckoutDate() {
713 var nowcheckin = jQuery('#checkindate').vboDatesRangePicker('getCheckinDate');
714 var nowcheckindate = new Date(nowcheckin.getTime());
715 nowcheckindate.setDate(nowcheckindate.getDate() + {$def_nights_cal});
716 jQuery('#checkindate').vboDatesRangePicker('checkout', 'minDate', nowcheckindate);
717 jQuery('#checkindate').vboDatesRangePicker('checkout', 'minStayNights', '{$def_nights_cal}');
718 jQuery('#checkindate').vboDatesRangePicker('checkout', 'setCheckoutDate', nowcheckindate);
719 }
720 JAVASCRIPT;
721
722 // push JS declaration
723 $declarations[] = $dtdecl;
724
725 // dates-range-picker rendering JS declaration
726 $numberOfMonths = $is_mobile ? 1 : 2;
727 $beforeShowDayIn = $wdaysrestrictions || $wdaysrestrictionsrange ? 'vbIsDayDisabled' : ($push_disabled_in ? 'vbIsDayFull' : 'vboCheckClosingDatesIn');
728 $beforeShowDayOut = $wdaysrestrictions || $wdaysrestrictionsrange ? 'vbIsDayDisabledCheckout' : ($push_disabled_out ? 'vbIsDayFullOut' : 'vboCheckClosingDatesOut');
729 $onSelectCheckin = $totrestrictions ? 'vbSetMinCheckoutDate(selectedDate);' : 'vbSetGlobalMinCheckoutDate();';
730
731 $declarations[] = <<<JAVASCRIPT
732 jQuery(function() {
733 // reset regional
734 jQuery.datepicker.setDefaults(jQuery.datepicker.regional['']);
735
736 // start DRP
737 jQuery('#checkindate').vboDatesRangePicker({
738 checkout: '#checkoutdate',
739 dateFormat: '{$juidf}',
740 showOn: 'focus',
741 numberOfMonths: {$numberOfMonths},
742 minDate: '{$min_days_advance}d',
743 maxDate: '{$max_date_future}',
744 beforeShowDay: {
745 checkin: {$beforeShowDayIn},
746 checkout: {$beforeShowDayOut},
747 },
748 onSelect: {
749 checkin: (selectedDate) => {
750 {$onSelectCheckin}
751 vbCalcNights();
752 },
753 checkout: (selectedDate) => {
754 vbCalcNights();
755 },
756 },
757 labels: {
758 checkin: Joomla.JText._('VBPICKUPROOM'),
759 checkout: Joomla.JText._('VBRETURNROOM'),
760 minStayNights: (nights) => {
761 return (Joomla.JText._('VBO_MIN_STAY_NIGHTS') + '').replace('%d', nights);
762 },
763 },
764 bottomCommands: {
765 clear: Joomla.JText._('VBO_CLEAR_DATES'),
766 close: Joomla.JText._('VBO_CLOSE'),
767 onClear: () => {
768 vbCalcNights();
769 },
770 },
771 });
772
773 // set proper regional
774 jQuery('#checkindate').datepicker('option', jQuery.datepicker.regional['vikbooking']);
775
776 // register additional triggers
777 jQuery('.vb-cal-img, .vbo-caltrigger').click(function() {
778 let dp = jQuery(this).prev('input');
779 if (!dp.length) {
780 return;
781 }
782 if (dp.hasClass('hasDatepicker')) {
783 dp.focus();
784 } else if (dp.attr('id') == 'checkoutdate') {
785 jQuery('#checkindate').focus();
786 }
787 });
788 });
789 JAVASCRIPT;
790
791 // add script declarations to document
792 $document->addScriptDeclaration(implode("\n", $declarations));
793
794 /**
795 * Render proper room/listing layout according to parameters.
796 *
797 * @since 1.17.3 (J) - 1.7.3 (WP)
798 */
799 if (!strcasecmp($layout, 'listing')) {
800 // render listing-style template
801 echo $this->loadTemplate('listing');
802 } else {
803 // fallback onto default room-style template
804 echo $this->loadTemplate('classic');
805 }
806