PluginProbe
Booking Calendar / 10.11.2
Booking Calendar v10.11.2
11.8.3 11.8.2 11.8.1 11.8 11.7 11.6.1 11.6 11.5 11.4.3 11.4.2 11.4.1 11.4 11.3 11.2.1 11.2 11.1 11.0 10.15.7 10.15.6 10.1.3 10.10 10.10.1 10.10.2 10.11 10.11.2 All 203 releases
booking / includes / __js / client / cal / wpbc_cal.js

wpbc_cal.js in Booking Calendar 10.11.2, at includes/__js/client/cal/wpbc_cal.js

2,099 lines 80.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * =====================================================================================================================
3 * includes/__js/cal/wpbc_cal.js
4 * =====================================================================================================================
5 */
6
7 /**
8 * Order or child booking resources saved here: _wpbc.booking__get_param_value( resource_id, 'resources_id_arr__in_dates' ) [2,10,12,11]
9 */
10
11 /**
12 * How to check booked times on specific date: ?
13 *
14 _wpbc.bookings_in_calendar__get_for_date(2,'2023-08-21');
15
16 console.log(
17 _wpbc.bookings_in_calendar__get_for_date(2,'2023-08-21')[2].booked_time_slots.merged_seconds,
18 _wpbc.bookings_in_calendar__get_for_date(2,'2023-08-21')[10].booked_time_slots.merged_seconds,
19 _wpbc.bookings_in_calendar__get_for_date(2,'2023-08-21')[11].booked_time_slots.merged_seconds,
20 _wpbc.bookings_in_calendar__get_for_date(2,'2023-08-21')[12].booked_time_slots.merged_seconds
21 );
22 * OR
23 console.log(
24 _wpbc.bookings_in_calendar__get_for_date(2,'2023-08-21')[2].booked_time_slots.merged_readable,
25 _wpbc.bookings_in_calendar__get_for_date(2,'2023-08-21')[10].booked_time_slots.merged_readable,
26 _wpbc.bookings_in_calendar__get_for_date(2,'2023-08-21')[11].booked_time_slots.merged_readable,
27 _wpbc.bookings_in_calendar__get_for_date(2,'2023-08-21')[12].booked_time_slots.merged_readable
28 );
29 *
30 */
31
32 /**
33 * Days selection:
34 * wpbc_calendar__unselect_all_dates( resource_id );
35 *
36 * var resource_id = 1;
37 * Example 1: var num_selected_days = wpbc_auto_select_dates_in_calendar( resource_id, '2024-05-15', '2024-05-25' );
38 * Example 2: var num_selected_days = wpbc_auto_select_dates_in_calendar( resource_id, ['2024-05-09','2024-05-19','2024-05-25'] );
39 *
40 */
41
42
43 /**
44 * C A L E N D A R ---------------------------------------------------------------------------------------------------
45 */
46
47
48 /**
49 * Show WPBC Calendar
50 *
51 * @param resource_id - resource ID
52 * @returns {boolean}
53 */
54 function wpbc_calendar_show( resource_id ){
55
56 // If no calendar HTML tag, then exit
57 if ( 0 === jQuery( '#calendar_booking' + resource_id ).length ){ return false; }
58
59 // If the calendar with the same Booking resource is activated already, then exit.
60 if ( true === jQuery( '#calendar_booking' + resource_id ).hasClass( 'hasDatepick' ) ){ return false; }
61
62 // -----------------------------------------------------------------------------------------------------------------
63 // Days selection
64 // -----------------------------------------------------------------------------------------------------------------
65 var local__is_range_select = false;
66 var local__multi_days_select_num = 365; // multiple | fixed
67 if ( 'dynamic' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ) ){
68 local__is_range_select = true;
69 local__multi_days_select_num = 0;
70 }
71 if ( 'single' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ) ){
72 local__multi_days_select_num = 0;
73 }
74
75 // -----------------------------------------------------------------------------------------------------------------
76 // Min - Max days to scroll/show
77 // -----------------------------------------------------------------------------------------------------------------
78 var local__min_date = 0;
79 local__min_date = new Date( _wpbc.get_other_param( 'today_arr' )[ 0 ], (parseInt( _wpbc.get_other_param( 'today_arr' )[ 1 ] ) - 1), _wpbc.get_other_param( 'today_arr' )[ 2 ], 0, 0, 0 ); // FixIn: 9.9.0.17.
80 //console.log( local__min_date );
81 var local__max_date = _wpbc.calendar__get_param_value( resource_id, 'booking_max_monthes_in_calendar' );
82 //local__max_date = new Date(2024, 5, 28); It is here issue of not selectable dates, but some dates showing in calendar as available, but we can not select it.
83
84 //// Define last day in calendar (as a last day of month (and not date, which is related to actual 'Today' date).
85 //// E.g. if today is 2023-09-25, and we set 'Number of months to scroll' as 5 months, then last day will be 2024-02-29 and not the 2024-02-25.
86 // var cal_last_day_in_month = jQuery.datepick._determineDate( null, local__max_date, new Date() );
87 // cal_last_day_in_month = new Date( cal_last_day_in_month.getFullYear(), cal_last_day_in_month.getMonth() + 1, 0 );
88 // local__max_date = cal_last_day_in_month; // FixIn: 10.0.0.26.
89
90 if ( ( location.href.indexOf('page=wpbc-new') != -1 )
91 && (
92 ( location.href.indexOf('booking_hash') != -1 ) // Comment this line for ability to add booking in past days at Booking > Add booking page.
93 || ( location.href.indexOf('allow_past') != -1 ) // FixIn: 10.7.1.2.
94 )
95 ){
96 local__min_date = null;
97 local__max_date = null;
98 }
99
100 var local__start_weekday = _wpbc.calendar__get_param_value( resource_id, 'booking_start_day_weeek' );
101 var local__number_of_months = parseInt( _wpbc.calendar__get_param_value( resource_id, 'calendar_number_of_months' ) );
102
103 jQuery( '#calendar_booking' + resource_id ).text( '' ); // Remove all HTML in calendar tag
104 // -----------------------------------------------------------------------------------------------------------------
105 // Show calendar
106 // -----------------------------------------------------------------------------------------------------------------
107 jQuery('#calendar_booking'+ resource_id).datepick(
108 {
109 beforeShowDay: function ( js_date ){
110 return wpbc__calendar__apply_css_to_days( js_date, {'resource_id': resource_id}, this );
111 },
112 onSelect: function ( string_dates, js_dates_arr ){ /**
113 * string_dates = '23.08.2023 - 26.08.2023' | '23.08.2023 - 23.08.2023' | '19.09.2023, 24.08.2023, 30.09.2023'
114 * js_dates_arr = range: [ Date (Aug 23 2023), Date (Aug 25 2023)] | multiple: [ Date(Oct 24 2023), Date(Oct 20 2023), Date(Oct 16 2023) ]
115 */
116 return wpbc__calendar__on_select_days( string_dates, {'resource_id': resource_id}, this );
117 },
118 onHover: function ( string_date, js_date ){
119 return wpbc__calendar__on_hover_days( string_date, js_date, {'resource_id': resource_id}, this );
120 },
121 onChangeMonthYear: function ( year, real_month, js_date__1st_day_in_month ){ },
122 showOn : 'both',
123 numberOfMonths: local__number_of_months,
124 stepMonths : 1,
125 // prevText : '«',
126 // nextText : '»',
127 prevText : '‹',
128 nextText : '›',
129 dateFormat : 'dd.mm.yy',
130 changeMonth : false,
131 changeYear : false,
132 minDate : local__min_date,
133 maxDate : local__max_date, // '1Y',
134 // minDate: new Date(2020, 2, 1), maxDate: new Date(2020, 9, 31), // Ability to set any start and end date in calendar
135 showStatus : false,
136 multiSeparator : ', ',
137 closeAtTop : false,
138 firstDay : local__start_weekday,
139 gotoCurrent : false,
140 hideIfNoPrevNext: true,
141 multiSelect : local__multi_days_select_num,
142 rangeSelect : local__is_range_select,
143 // showWeeks: true,
144 useThemeRoller: false
145 }
146 );
147
148
149
150 // -----------------------------------------------------------------------------------------------------------------
151 // Clear today date highlighting
152 // -----------------------------------------------------------------------------------------------------------------
153 setTimeout( function (){ wpbc_calendars__clear_days_highlighting( resource_id ); }, 500 ); // FixIn: 7.1.2.8.
154
155 // -----------------------------------------------------------------------------------------------------------------
156 // Scroll calendar to specific month
157 // -----------------------------------------------------------------------------------------------------------------
158 var start_bk_month = _wpbc.calendar__get_param_value( resource_id, 'calendar_scroll_to' );
159 if ( false !== start_bk_month ){
160 wpbc_calendar__scroll_to( resource_id, start_bk_month[ 0 ], start_bk_month[ 1 ] );
161 }
162 }
163
164
165 /**
166 * Apply CSS to calendar date cells
167 *
168 * @param date - JavaScript Date Obj: Mon Dec 11 2023 00:00:00 GMT+0200 (Eastern European Standard Time)
169 * @param calendar_params_arr - Calendar Settings Object: {
170 * "resource_id": 4
171 * }
172 * @param datepick_this - this of datepick Obj
173 * @returns {(*|string)[]|(boolean|string)[]} - [ {true -available | false - unavailable}, 'CSS classes for calendar day cell' ]
174 */
175 function wpbc__calendar__apply_css_to_days( date, calendar_params_arr, datepick_this ){
176
177 var today_date = new Date( _wpbc.get_other_param( 'today_arr' )[ 0 ], (parseInt( _wpbc.get_other_param( 'today_arr' )[ 1 ] ) - 1), _wpbc.get_other_param( 'today_arr' )[ 2 ], 0, 0, 0 ); // Today JS_Date_Obj.
178 var class_day = wpbc__get__td_class_date( date ); // '1-9-2023'
179 var sql_class_day = wpbc__get__sql_class_date( date ); // '2023-01-09'
180 var resource_id = ( 'undefined' !== typeof(calendar_params_arr[ 'resource_id' ]) ) ? calendar_params_arr[ 'resource_id' ] : '1'; // '1'
181
182 // Get Selected dates in calendar
183 var selected_dates_sql = wpbc_get__selected_dates_sql__as_arr( resource_id );
184
185 // Get Data --------------------------------------------------------------------------------------------------------
186 var date_bookings_obj = _wpbc.bookings_in_calendar__get_for_date( resource_id, sql_class_day );
187
188
189 // Array with CSS classes for date ---------------------------------------------------------------------------------
190 var css_classes__for_date = [];
191 css_classes__for_date.push( 'sql_date_' + sql_class_day ); // 'sql_date_2023-07-21'
192 css_classes__for_date.push( 'cal4date-' + class_day ); // 'cal4date-7-21-2023'
193 css_classes__for_date.push( 'wpbc_weekday_' + date.getDay() ); // 'wpbc_weekday_4'
194
195 // Define Selected Check In/Out dates in TD -----------------------------------------------------------------------
196 if (
197 ( selected_dates_sql.length )
198 //&& ( selected_dates_sql[ 0 ] !== selected_dates_sql[ (selected_dates_sql.length - 1) ] )
199 ){
200 if ( sql_class_day === selected_dates_sql[ 0 ] ){
201 css_classes__for_date.push( 'selected_check_in' );
202 css_classes__for_date.push( 'selected_check_in_out' );
203 }
204 if ( ( selected_dates_sql.length > 1 ) && ( sql_class_day === selected_dates_sql[ (selected_dates_sql.length - 1) ] ) ) {
205 css_classes__for_date.push( 'selected_check_out' );
206 css_classes__for_date.push( 'selected_check_in_out' );
207 }
208 }
209
210
211 var is_day_selectable = false;
212
213 // If something not defined, then this date closed ---------------------------------------------------------------
214 if ( false === date_bookings_obj ){
215
216 css_classes__for_date.push( 'date_user_unavailable' );
217
218 return [ is_day_selectable, css_classes__for_date.join(' ') ];
219 }
220
221
222 // -----------------------------------------------------------------------------------------------------------------
223 // date_bookings_obj - Defined. Dates can be selectable.
224 // -----------------------------------------------------------------------------------------------------------------
225
226 // -----------------------------------------------------------------------------------------------------------------
227 // Add season names to the day CSS classes -- it is required for correct work of conditional fields --------------
228 var season_names_arr = _wpbc.seasons__get_for_date( resource_id, sql_class_day );
229
230 for ( var season_key in season_names_arr ){
231
232 css_classes__for_date.push( season_names_arr[ season_key ] ); // 'wpdevbk_season_september_2023'
233 }
234 // -----------------------------------------------------------------------------------------------------------------
235
236
237 // Cost Rate -------------------------------------------------------------------------------------------------------
238 css_classes__for_date.push( 'rate_' + date_bookings_obj[ resource_id ][ 'date_cost_rate' ].toString().replace( /[\.\s]/g, '_' ) ); // 'rate_99_00' -> 99.00
239
240
241 if ( parseInt( date_bookings_obj[ 'day_availability' ] ) > 0 ){
242 is_day_selectable = true;
243 css_classes__for_date.push( 'date_available' );
244 css_classes__for_date.push( 'reserved_days_count' + parseInt( date_bookings_obj[ 'max_capacity' ] - date_bookings_obj[ 'day_availability' ] ) );
245 } else {
246 is_day_selectable = false;
247 css_classes__for_date.push( 'date_user_unavailable' );
248 }
249
250
251 switch ( date_bookings_obj[ 'summary']['status_for_day' ] ){
252
253 case 'available':
254 break;
255
256 case 'time_slots_booking':
257 css_classes__for_date.push( 'timespartly', 'times_clock' );
258 break;
259
260 case 'full_day_booking':
261 css_classes__for_date.push( 'full_day_booking' );
262 break;
263
264 case 'season_filter':
265 css_classes__for_date.push( 'date_user_unavailable', 'season_unavailable' );
266 date_bookings_obj[ 'summary']['status_for_bookings' ] = ''; // Reset booking status color for possible old bookings on this date
267 break;
268
269 case 'resource_availability':
270 css_classes__for_date.push( 'date_user_unavailable', 'resource_unavailable' );
271 date_bookings_obj[ 'summary']['status_for_bookings' ] = ''; // Reset booking status color for possible old bookings on this date
272 break;
273
274 case 'weekday_unavailable':
275 css_classes__for_date.push( 'date_user_unavailable', 'weekday_unavailable' );
276 date_bookings_obj[ 'summary']['status_for_bookings' ] = ''; // Reset booking status color for possible old bookings on this date
277 break;
278
279 case 'from_today_unavailable':
280 css_classes__for_date.push( 'date_user_unavailable', 'from_today_unavailable' );
281 date_bookings_obj[ 'summary']['status_for_bookings' ] = ''; // Reset booking status color for possible old bookings on this date
282 break;
283
284 case 'limit_available_from_today':
285 css_classes__for_date.push( 'date_user_unavailable', 'limit_available_from_today' );
286 date_bookings_obj[ 'summary']['status_for_bookings' ] = ''; // Reset booking status color for possible old bookings on this date
287 break;
288
289 case 'change_over':
290 /*
291 *
292 // check_out_time_date2approve check_in_time_date2approve
293 // check_out_time_date2approve check_in_time_date_approved
294 // check_in_time_date2approve check_out_time_date_approved
295 // check_out_time_date_approved check_in_time_date_approved
296 */
297
298 css_classes__for_date.push( 'timespartly', 'check_in_time', 'check_out_time' );
299 // FixIn: 10.0.0.2.
300 if ( date_bookings_obj[ 'summary' ][ 'status_for_bookings' ].indexOf( 'approved_pending' ) > -1 ){
301 css_classes__for_date.push( 'check_out_time_date_approved', 'check_in_time_date2approve' );
302 }
303 if ( date_bookings_obj[ 'summary' ][ 'status_for_bookings' ].indexOf( 'pending_approved' ) > -1 ){
304 css_classes__for_date.push( 'check_out_time_date2approve', 'check_in_time_date_approved' );
305 }
306 break;
307
308 case 'check_in':
309 css_classes__for_date.push( 'timespartly', 'check_in_time' );
310
311 // FixIn: 9.9.0.33.
312 if ( date_bookings_obj[ 'summary' ][ 'status_for_bookings' ].indexOf( 'pending' ) > -1 ){
313 css_classes__for_date.push( 'check_in_time_date2approve' );
314 } else if ( date_bookings_obj[ 'summary' ][ 'status_for_bookings' ].indexOf( 'approved' ) > -1 ){
315 css_classes__for_date.push( 'check_in_time_date_approved' );
316 }
317 break;
318
319 case 'check_out':
320 css_classes__for_date.push( 'timespartly', 'check_out_time' );
321
322 // FixIn: 9.9.0.33.
323 if ( date_bookings_obj[ 'summary' ][ 'status_for_bookings' ].indexOf( 'pending' ) > -1 ){
324 css_classes__for_date.push( 'check_out_time_date2approve' );
325 } else if ( date_bookings_obj[ 'summary' ][ 'status_for_bookings' ].indexOf( 'approved' ) > -1 ){
326 css_classes__for_date.push( 'check_out_time_date_approved' );
327 }
328 break;
329
330 default:
331 // mixed statuses: 'change_over check_out' .... variations.... check more in function wpbc_get_availability_per_days_arr()
332 date_bookings_obj[ 'summary']['status_for_day' ] = 'available';
333 }
334
335
336
337 if ( 'available' != date_bookings_obj[ 'summary']['status_for_day' ] ){
338
339 var is_set_pending_days_selectable = _wpbc.calendar__get_param_value( resource_id, 'pending_days_selectable' ); // set pending days selectable // FixIn: 8.6.1.18.
340
341 switch ( date_bookings_obj[ 'summary']['status_for_bookings' ] ){
342
343 case '':
344 // Usually it's means that day is available or unavailable without the bookings
345 break;
346
347 case 'pending':
348 css_classes__for_date.push( 'date2approve' );
349 is_day_selectable = (is_day_selectable) ? true : is_set_pending_days_selectable;
350 break;
351
352 case 'approved':
353 css_classes__for_date.push( 'date_approved' );
354 break;
355
356 // Situations for "change-over" days: ----------------------------------------------------------------------
357 case 'pending_pending':
358 css_classes__for_date.push( 'check_out_time_date2approve', 'check_in_time_date2approve' );
359 is_day_selectable = (is_day_selectable) ? true : is_set_pending_days_selectable;
360 break;
361
362 case 'pending_approved':
363 css_classes__for_date.push( 'check_out_time_date2approve', 'check_in_time_date_approved' );
364 is_day_selectable = (is_day_selectable) ? true : is_set_pending_days_selectable;
365 break;
366
367 case 'approved_pending':
368 css_classes__for_date.push( 'check_out_time_date_approved', 'check_in_time_date2approve' );
369 is_day_selectable = (is_day_selectable) ? true : is_set_pending_days_selectable;
370 break;
371
372 case 'approved_approved':
373 css_classes__for_date.push( 'check_out_time_date_approved', 'check_in_time_date_approved' );
374 break;
375
376 default:
377
378 }
379 }
380
381 return [ is_day_selectable, css_classes__for_date.join( ' ' ) ];
382 }
383
384
385 /**
386 * Mouseover calendar date cells
387 *
388 * @param string_date
389 * @param date - JavaScript Date Obj: Mon Dec 11 2023 00:00:00 GMT+0200 (Eastern European Standard Time)
390 * @param calendar_params_arr - Calendar Settings Object: {
391 * "resource_id": 4
392 * }
393 * @param datepick_this - this of datepick Obj
394 * @returns {boolean}
395 */
396 function wpbc__calendar__on_hover_days( string_date, date, calendar_params_arr, datepick_this ) {
397
398 if ( null === date ) {
399 wpbc_calendars__clear_days_highlighting( ('undefined' !== typeof (calendar_params_arr[ 'resource_id' ])) ? calendar_params_arr[ 'resource_id' ] : '1' ); // FixIn: 10.5.2.4.
400 return false;
401 }
402
403 var class_day = wpbc__get__td_class_date( date ); // '1-9-2023'
404 var sql_class_day = wpbc__get__sql_class_date( date ); // '2023-01-09'
405 var resource_id = ( 'undefined' !== typeof(calendar_params_arr[ 'resource_id' ]) ) ? calendar_params_arr[ 'resource_id' ] : '1'; // '1'
406
407 // Get Data --------------------------------------------------------------------------------------------------------
408 var date_booking_obj = _wpbc.bookings_in_calendar__get_for_date( resource_id, sql_class_day ); // {...}
409
410 if ( ! date_booking_obj ){ return false; }
411
412
413 // T o o l t i p s -------------------------------------------------------------------------------------------------
414 var tooltip_text = '';
415 if ( date_booking_obj[ 'summary']['tooltip_availability' ].length > 0 ){
416 tooltip_text += date_booking_obj[ 'summary']['tooltip_availability' ];
417 }
418 if ( date_booking_obj[ 'summary']['tooltip_day_cost' ].length > 0 ){
419 tooltip_text += date_booking_obj[ 'summary']['tooltip_day_cost' ];
420 }
421 if ( date_booking_obj[ 'summary']['tooltip_times' ].length > 0 ){
422 tooltip_text += date_booking_obj[ 'summary']['tooltip_times' ];
423 }
424 if ( date_booking_obj[ 'summary']['tooltip_booking_details' ].length > 0 ){
425 tooltip_text += date_booking_obj[ 'summary']['tooltip_booking_details' ];
426 }
427 wpbc_set_tooltip___for__calendar_date( tooltip_text, resource_id, class_day );
428
429
430
431 // U n h o v e r i n g in UNSELECTABLE_CALENDAR ------------------------------------------------------------
432 var is_unselectable_calendar = ( jQuery( '#calendar_booking_unselectable' + resource_id ).length > 0); // FixIn: 8.0.1.2.
433 var is_booking_form_exist = ( jQuery( '#booking_form_div' + resource_id ).length > 0 );
434
435 if ( ( is_unselectable_calendar ) && ( ! is_booking_form_exist ) ){
436
437 /**
438 * Un Hover all dates in calendar (without the booking form), if only Availability Calendar here and we do not insert Booking form by mistake.
439 */
440
441 wpbc_calendars__clear_days_highlighting( resource_id ); // Clear days highlighting
442
443 var css_of_calendar = '.wpbc_only_calendar #calendar_booking' + resource_id;
444 jQuery( css_of_calendar + ' .datepick-days-cell, '
445 + css_of_calendar + ' .datepick-days-cell a' ).css( 'cursor', 'default' ); // Set cursor to Default
446 return false;
447 }
448
449
450
451 // D a y s H o v e r i n g ------------------------------------------------------------------------------------
452 if (
453 ( location.href.indexOf( 'page=wpbc' ) == -1 )
454 || ( location.href.indexOf( 'page=wpbc-new' ) > 0 )
455 || ( location.href.indexOf( 'page=wpbc-setup' ) > 0 )
456 || ( location.href.indexOf( 'page=wpbc-availability' ) > 0 )
457 || ( ( location.href.indexOf( 'page=wpbc-settings' ) > 0 ) &&
458 ( location.href.indexOf( '&tab=form' ) > 0 )
459 )
460 ){
461 // The same as dates selection, but for days hovering
462
463 if ( 'function' == typeof( wpbc__calendar__do_days_highlight__bs ) ){
464 wpbc__calendar__do_days_highlight__bs( sql_class_day, date, resource_id );
465 }
466 }
467
468 }
469
470
471 /**
472 * Select calendar date cells
473 *
474 * @param date - JavaScript Date Obj: Mon Dec 11 2023 00:00:00 GMT+0200 (Eastern European Standard Time)
475 * @param calendar_params_arr - Calendar Settings Object: {
476 * "resource_id": 4
477 * }
478 * @param datepick_this - this of datepick Obj
479 *
480 */
481 function wpbc__calendar__on_select_days( date, calendar_params_arr, datepick_this ){
482
483 var resource_id = ( 'undefined' !== typeof(calendar_params_arr[ 'resource_id' ]) ) ? calendar_params_arr[ 'resource_id' ] : '1'; // '1'
484
485 // Set unselectable, if only Availability Calendar here (and we do not insert Booking form by mistake).
486 var is_unselectable_calendar = ( jQuery( '#calendar_booking_unselectable' + resource_id ).length > 0); // FixIn: 8.0.1.2.
487 var is_booking_form_exist = ( jQuery( '#booking_form_div' + resource_id ).length > 0 );
488 if ( ( is_unselectable_calendar ) && ( ! is_booking_form_exist ) ){
489 wpbc_calendar__unselect_all_dates( resource_id ); // Unselect Dates
490 jQuery('.wpbc_only_calendar .popover_calendar_hover').remove(); // Hide all opened popovers
491 return false;
492 }
493
494 jQuery( '#date_booking' + resource_id ).val( date ); // Add selected dates to hidden textarea
495
496
497 if ( 'function' === typeof (wpbc__calendar__do_days_select__bs) ){ wpbc__calendar__do_days_select__bs( date, resource_id ); }
498
499 wpbc_disable_time_fields_in_booking_form( resource_id );
500
501 // Hook -- trigger day selection -----------------------------------------------------------------------------------
502 var mouse_clicked_dates = date; // Can be: "05.10.2023 - 07.10.2023" | "10.10.2023 - 10.10.2023" |
503 var all_selected_dates_arr = wpbc_get__selected_dates_sql__as_arr( resource_id ); // Can be: [ "2023-10-05", "2023-10-06", "2023-10-07", … ]
504 jQuery( ".booking_form_div" ).trigger( "date_selected", [ resource_id, mouse_clicked_dates, all_selected_dates_arr ] );
505 }
506
507 // Mark middle selected dates with 0.5 opacity // FixIn: 10.3.0.9.
508 jQuery( document ).ready( function (){
509 jQuery( ".booking_form_div" ).on( 'date_selected', function ( event, resource_id, date ){
510 if (
511 ( 'fixed' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ))
512 || ('dynamic' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ))
513 ){
514 var closed_timer = setTimeout( function (){
515 var middle_days_opacity = _wpbc.get_other_param( 'calendars__days_selection__middle_days_opacity' );
516 jQuery( '#calendar_booking' + resource_id + ' .datepick-current-day' ).not( ".selected_check_in_out" ).css( 'opacity', middle_days_opacity );
517 }, 10 );
518 }
519 } );
520 } );
521
522
523 /**
524 * -- T i m e F i e l d s start --------------------------------------------------------------------------
525 */
526
527 /**
528 * Disable time slots in booking form depend on selected dates and booked dates/times
529 *
530 * @param resource_id
531 */
532 function wpbc_disable_time_fields_in_booking_form( resource_id ){
533
534 /**
535 * 1. Get all time fields in the booking form as array of objects
536 * [
537 * { jquery_option: jQuery_Object {}
538 * name: 'rangetime2[]'
539 * times_as_seconds: [ 21600, 23400 ]
540 * value_option_24h: '06:00 - 06:30'
541 * }
542 * ...
543 * { jquery_option: jQuery_Object {}
544 * name: 'starttime2[]'
545 * times_as_seconds: [ 21600 ]
546 * value_option_24h: '06:00'
547 * }
548 * ]
549 */
550 var time_fields_obj_arr = wpbc_get__time_fields__in_booking_form__as_arr( resource_id );
551
552 // 2. Get all selected dates in SQL format like this [ "2023-08-23", "2023-08-24", "2023-08-25", ... ]
553 var selected_dates_arr = wpbc_get__selected_dates_sql__as_arr( resource_id );
554
555 // 3. Get child booking resources or single booking resource that exist in dates
556 var child_resources_arr = wpbc_clone_obj( _wpbc.booking__get_param_value( resource_id, 'resources_id_arr__in_dates' ) );
557
558 var sql_date;
559 var child_resource_id;
560 var merged_seconds;
561 var time_fields_obj;
562 var is_intersect;
563 var is_check_in;
564
565 var today_time__real = new Date( _wpbc.get_other_param( 'time_local_arr' )[0], ( parseInt( _wpbc.get_other_param( 'time_local_arr' )[1] ) - 1), _wpbc.get_other_param( 'time_local_arr' )[2], _wpbc.get_other_param( 'time_local_arr' )[3], _wpbc.get_other_param( 'time_local_arr' )[4], 0 );
566 var today_time__shift = new Date( _wpbc.get_other_param( 'today_arr' )[0], ( parseInt( _wpbc.get_other_param( 'today_arr' )[1] ) - 1), _wpbc.get_other_param( 'today_arr' )[2], _wpbc.get_other_param( 'today_arr' )[3], _wpbc.get_other_param( 'today_arr' )[4], 0 );
567
568 // 4. Loop all time Fields options // FixIn: 10.3.0.2.
569 for ( let field_key = 0; field_key < time_fields_obj_arr.length; field_key++ ){
570
571 time_fields_obj_arr[ field_key ].disabled = 0; // By default, this time field is not disabled.
572
573 time_fields_obj = time_fields_obj_arr[ field_key ]; // { times_as_seconds: [ 21600, 23400 ], value_option_24h: '06:00 - 06:30', name: 'rangetime2[]', jquery_option: jQuery_Object {}}
574
575 // Loop all selected dates.
576 for ( var i = 0; i < selected_dates_arr.length; i++ ) {
577
578 // Get Date: '2023-08-18'.
579 sql_date = selected_dates_arr[ i ];
580
581 var is_time_in_past = wpbc_check_is_time_in_past( today_time__shift, sql_date, time_fields_obj );
582 if ( is_time_in_past ) {
583 // This time for selected date already in the past.
584 time_fields_obj_arr[field_key].disabled = 1;
585 break; // exist from Dates LOOP.
586 }
587
588 // FixIn: 9.9.0.31.
589 if (
590 ( 'Off' === _wpbc.calendar__get_param_value( resource_id, 'booking_recurrent_time' ) )
591 && ( selected_dates_arr.length>1 )
592 ){
593 //TODO: skip some fields checking if it's start / end time for mulple dates selection mode.
594 //TODO: we need to fix situation for entimes, when user select several dates, and in start time booked 00:00 - 15:00 , but systsme block untill 15:00 the end time as well, which is wrong, because it 2 or 3 dates selection and end date can be fullu available
595
596 if ( (0 == i) && (time_fields_obj[ 'name' ].indexOf( 'endtime' ) >= 0) ){
597 break;
598 }
599 if ( ( (selected_dates_arr.length-1) == i ) && (time_fields_obj[ 'name' ].indexOf( 'starttime' ) >= 0) ){
600 break;
601 }
602 }
603
604
605
606 var how_many_resources_intersected = 0;
607 // Loop all resources ID
608 // for ( var res_key in child_resources_arr ){ // FixIn: 10.3.0.2.
609 for ( let res_key = 0; res_key < child_resources_arr.length; res_key++ ){
610
611 child_resource_id = child_resources_arr[ res_key ];
612
613 // _wpbc.bookings_in_calendar__get_for_date(2,'2023-08-21')[12].booked_time_slots.merged_seconds = [ "07:00:11 - 07:30:02", "10:00:11 - 00:00:00" ]
614 // _wpbc.bookings_in_calendar__get_for_date(2,'2023-08-21')[2].booked_time_slots.merged_seconds = [ [ 25211, 27002 ], [ 36011, 86400 ] ]
615
616 if ( false !== _wpbc.bookings_in_calendar__get_for_date( resource_id, sql_date ) ){
617 merged_seconds = _wpbc.bookings_in_calendar__get_for_date( resource_id, sql_date )[ child_resource_id ].booked_time_slots.merged_seconds; // [ [ 25211, 27002 ], [ 36011, 86400 ] ]
618 } else {
619 merged_seconds = [];
620 }
621 if ( time_fields_obj.times_as_seconds.length > 1 ){
622 is_intersect = wpbc_is_intersect__range_time_interval( [
623 [
624 ( parseInt( time_fields_obj.times_as_seconds[0] ) + 20 ),
625 ( parseInt( time_fields_obj.times_as_seconds[1] ) - 20 )
626 ]
627 ]
628 , merged_seconds );
629 } else {
630 is_check_in = (-1 !== time_fields_obj.name.indexOf( 'start' ));
631 is_intersect = wpbc_is_intersect__one_time_interval(
632 ( ( is_check_in )
633 ? parseInt( time_fields_obj.times_as_seconds ) + 20
634 : parseInt( time_fields_obj.times_as_seconds ) - 20
635 )
636 , merged_seconds );
637 }
638 if (is_intersect){
639 how_many_resources_intersected++; // Increase
640 }
641
642 }
643
644 if ( child_resources_arr.length == how_many_resources_intersected ) {
645 // All resources intersected, then it's means that this time-slot or time must be Disabled, and we can exist from selected_dates_arr LOOP
646
647 time_fields_obj_arr[ field_key ].disabled = 1;
648 break; // exist from Dates LOOP
649 }
650 }
651 }
652
653
654 // 5. Now we can disable time slot in HTML by using ( field.disabled == 1 ) property
655 wpbc__html__time_field_options__set_disabled( time_fields_obj_arr );
656
657 jQuery( ".booking_form_div" ).trigger( 'wpbc_hook_timeslots_disabled', [resource_id, selected_dates_arr] ); // Trigger hook on disabling timeslots. Usage: jQuery( ".booking_form_div" ).on( 'wpbc_hook_timeslots_disabled', function ( event, bk_type, all_dates ){ ... } ); // FixIn: 8.7.11.9.
658 }
659
660
661 /**
662 * Check if specific time(-slot) already in the past for selected date
663 *
664 * @param js_current_time_to_check - JS Date
665 * @param sql_date - '2025-01-26'
666 * @param time_fields_obj - Object
667 * @returns {boolean}
668 */
669 function wpbc_check_is_time_in_past( js_current_time_to_check, sql_date, time_fields_obj ) {
670
671 // FixIn: 10.9.6.4
672 var sql_date_arr = sql_date.split( '-' );
673 var sql_date__midnight = new Date( parseInt( sql_date_arr[0] ), ( parseInt( sql_date_arr[1] ) - 1 ), parseInt( sql_date_arr[2] ), 0, 0, 0 );
674 var sql_date__midnight_miliseconds = sql_date__midnight.getTime();
675
676 var is_intersect = false;
677
678 if ( time_fields_obj.times_as_seconds.length > 1 ) {
679
680 if ( js_current_time_to_check.getTime() > (sql_date__midnight_miliseconds + (parseInt( time_fields_obj.times_as_seconds[0] ) + 20) * 1000) ) {
681 is_intersect = true;
682 }
683 if ( js_current_time_to_check.getTime() > (sql_date__midnight_miliseconds + (parseInt( time_fields_obj.times_as_seconds[1] ) - 20) * 1000) ) {
684 is_intersect = true;
685 }
686
687 } else {
688 var is_check_in = (-1 !== time_fields_obj.name.indexOf( 'start' ));
689
690 var times_as_seconds_check = (is_check_in) ? parseInt( time_fields_obj.times_as_seconds ) + 20 : parseInt( time_fields_obj.times_as_seconds ) - 20;
691
692 times_as_seconds_check = sql_date__midnight_miliseconds + times_as_seconds_check * 1000;
693
694 if ( js_current_time_to_check.getTime() > times_as_seconds_check ) {
695 is_intersect = true;
696 }
697 }
698
699 return is_intersect;
700 }
701
702 /**
703 * Is number inside /intersect of array of intervals ?
704 *
705 * @param time_A - 25800
706 * @param time_interval_B - [ [ 25211, 27002 ], [ 36011, 86400 ] ]
707 * @returns {boolean}
708 */
709 function wpbc_is_intersect__one_time_interval( time_A, time_interval_B ){
710
711 for ( var j = 0; j < time_interval_B.length; j++ ){
712
713 if ( (parseInt( time_A ) > parseInt( time_interval_B[ j ][ 0 ] )) && (parseInt( time_A ) < parseInt( time_interval_B[ j ][ 1 ] )) ){
714 return true
715 }
716
717 // if ( ( parseInt( time_A ) == parseInt( time_interval_B[ j ][ 0 ] ) ) || ( parseInt( time_A ) == parseInt( time_interval_B[ j ][ 1 ] ) ) ) {
718 // // Time A just at the border of interval
719 // }
720 }
721
722 return false;
723 }
724
725 /**
726 * Is these array of intervals intersected ?
727 *
728 * @param time_interval_A - [ [ 21600, 23400 ] ]
729 * @param time_interval_B - [ [ 25211, 27002 ], [ 36011, 86400 ] ]
730 * @returns {boolean}
731 */
732 function wpbc_is_intersect__range_time_interval( time_interval_A, time_interval_B ){
733
734 var is_intersect;
735
736 for ( var i = 0; i < time_interval_A.length; i++ ){
737
738 for ( var j = 0; j < time_interval_B.length; j++ ){
739
740 is_intersect = wpbc_intervals__is_intersected( time_interval_A[ i ], time_interval_B[ j ] );
741
742 if ( is_intersect ){
743 return true;
744 }
745 }
746 }
747
748 return false;
749 }
750
751 /**
752 * Get all time fields in the booking form as array of objects
753 *
754 * @param resource_id
755 * @returns []
756 *
757 * Example:
758 * [
759 * {
760 * value_option_24h: '06:00 - 06:30'
761 * times_as_seconds: [ 21600, 23400 ]
762 * jquery_option: jQuery_Object {}
763 * name: 'rangetime2[]'
764 * }
765 * ...
766 * {
767 * value_option_24h: '06:00'
768 * times_as_seconds: [ 21600 ]
769 * jquery_option: jQuery_Object {}
770 * name: 'starttime2[]'
771 * }
772 * ]
773 */
774 function wpbc_get__time_fields__in_booking_form__as_arr( resource_id ){
775 /**
776 * Fields with [] like this select[name="rangetime1[]"]
777 * it's when we have 'multiple' in shortcode: [select* rangetime multiple "06:00 - 06:30" ... ]
778 */
779 var time_fields_arr=[
780 'select[name="rangetime' + resource_id + '"]',
781 'select[name="rangetime' + resource_id + '[]"]',
782 'select[name="starttime' + resource_id + '"]',
783 'select[name="starttime' + resource_id + '[]"]',
784 'select[name="endtime' + resource_id + '"]',
785 'select[name="endtime' + resource_id + '[]"]'
786 ];
787
788 var time_fields_obj_arr = [];
789
790 // Loop all Time Fields
791 for ( var ctf= 0; ctf < time_fields_arr.length; ctf++ ){
792
793 var time_field = time_fields_arr[ ctf ];
794 var time_option = jQuery( time_field + ' option' );
795
796 // Loop all options in time field
797 for ( var j = 0; j < time_option.length; j++ ){
798
799 var jquery_option = jQuery( time_field + ' option:eq(' + j + ')' );
800 var value_option_seconds_arr = jquery_option.val().split( '-' );
801 var times_as_seconds = [];
802
803 // Get time as seconds
804 if ( value_option_seconds_arr.length ){ // FixIn: 9.8.10.1.
805 for ( let i = 0; i < value_option_seconds_arr.length; i++ ){ // FixIn: 10.0.0.56.
806 // value_option_seconds_arr[i] = '14:00 ' | ' 16:00' (if from 'rangetime') and '16:00' if (start/end time)
807
808 var start_end_times_arr = value_option_seconds_arr[ i ].trim().split( ':' );
809
810 var time_in_seconds = parseInt( start_end_times_arr[ 0 ] ) * 60 * 60 + parseInt( start_end_times_arr[ 1 ] ) * 60;
811
812 times_as_seconds.push( time_in_seconds );
813 }
814 }
815
816 time_fields_obj_arr.push( {
817 'name' : jQuery( time_field ).attr( 'name' ),
818 'value_option_24h': jquery_option.val(),
819 'jquery_option' : jquery_option,
820 'times_as_seconds': times_as_seconds
821 } );
822 }
823 }
824
825 return time_fields_obj_arr;
826 }
827
828 /**
829 * Disable HTML options and add booked CSS class
830 *
831 * @param time_fields_obj_arr - this value is from the func: wpbc_get__time_fields__in_booking_form__as_arr( resource_id )
832 * [
833 * { jquery_option: jQuery_Object {}
834 * name: 'rangetime2[]'
835 * times_as_seconds: [ 21600, 23400 ]
836 * value_option_24h: '06:00 - 06:30'
837 * disabled = 1
838 * }
839 * ...
840 * { jquery_option: jQuery_Object {}
841 * name: 'starttime2[]'
842 * times_as_seconds: [ 21600 ]
843 * value_option_24h: '06:00'
844 * disabled = 0
845 * }
846 * ]
847 *
848 */
849 function wpbc__html__time_field_options__set_disabled( time_fields_obj_arr ){
850
851 var jquery_option;
852
853 for ( var i = 0; i < time_fields_obj_arr.length; i++ ){
854
855 var jquery_option = time_fields_obj_arr[ i ].jquery_option;
856
857 if ( 1 == time_fields_obj_arr[ i ].disabled ){
858 jquery_option.prop( 'disabled', true ); // Make disable some options
859 jquery_option.addClass( 'booked' ); // Add "booked" CSS class
860
861 // if this booked element selected --> then deselect it
862 if ( jquery_option.prop( 'selected' ) ){
863 jquery_option.prop( 'selected', false );
864
865 jquery_option.parent().find( 'option:not([disabled]):first' ).prop( 'selected', true ).trigger( "change" );
866 }
867
868 } else {
869 jquery_option.prop( 'disabled', false ); // Make active all times
870 jquery_option.removeClass( 'booked' ); // Remove class "booked"
871 }
872 }
873
874 }
875
876 /**
877 * Check if this time_range | Time_Slot is Full Day booked
878 *
879 * @param timeslot_arr_in_seconds - [ 36011, 86400 ]
880 * @returns {boolean}
881 */
882 function wpbc_is_this_timeslot__full_day_booked( timeslot_arr_in_seconds ){
883
884 if (
885 ( timeslot_arr_in_seconds.length > 1 )
886 && ( parseInt( timeslot_arr_in_seconds[ 0 ] ) < 30 )
887 && ( parseInt( timeslot_arr_in_seconds[ 1 ] ) > ( (24 * 60 * 60) - 30) )
888 ){
889 return true;
890 }
891
892 return false;
893 }
894
895
896 // -----------------------------------------------------------------------------------------------------------------
897 /* == S e l e c t e d D a t e s / T i m e - F i e l d s ==
898 // ----------------------------------------------------------------------------------------------------------------- */
899
900 /**
901 * Get all selected dates in SQL format like this [ "2023-08-23", "2023-08-24" , ... ]
902 *
903 * @param resource_id
904 * @returns {[]} [ "2023-08-23", "2023-08-24", "2023-08-25", "2023-08-26", "2023-08-27", "2023-08-28", "2023-08-29" ]
905 */
906 function wpbc_get__selected_dates_sql__as_arr( resource_id ){
907
908 var selected_dates_arr = [];
909 selected_dates_arr = jQuery( '#date_booking' + resource_id ).val().split(',');
910
911 if ( selected_dates_arr.length ){ // FixIn: 9.8.10.1.
912 for ( let i = 0; i < selected_dates_arr.length; i++ ){ // FixIn: 10.0.0.56.
913 selected_dates_arr[ i ] = selected_dates_arr[ i ].trim();
914 selected_dates_arr[ i ] = selected_dates_arr[ i ].split( '.' );
915 if ( selected_dates_arr[ i ].length > 1 ){
916 selected_dates_arr[ i ] = selected_dates_arr[ i ][ 2 ] + '-' + selected_dates_arr[ i ][ 1 ] + '-' + selected_dates_arr[ i ][ 0 ];
917 }
918 }
919 }
920
921 // Remove empty elements from an array
922 selected_dates_arr = selected_dates_arr.filter( function ( n ){ return parseInt(n); } );
923
924 selected_dates_arr.sort();
925
926 return selected_dates_arr;
927 }
928
929
930 /**
931 * Get all time fields in the booking form as array of objects
932 *
933 * @param resource_id
934 * @param is_only_selected_time
935 * @returns []
936 *
937 * Example:
938 * [
939 * {
940 * value_option_24h: '06:00 - 06:30'
941 * times_as_seconds: [ 21600, 23400 ]
942 * jquery_option: jQuery_Object {}
943 * name: 'rangetime2[]'
944 * }
945 * ...
946 * {
947 * value_option_24h: '06:00'
948 * times_as_seconds: [ 21600 ]
949 * jquery_option: jQuery_Object {}
950 * name: 'starttime2[]'
951 * }
952 * ]
953 */
954 function wpbc_get__selected_time_fields__in_booking_form__as_arr( resource_id, is_only_selected_time = true ){
955 /**
956 * Fields with [] like this select[name="rangetime1[]"]
957 * it's when we have 'multiple' in shortcode: [select* rangetime multiple "06:00 - 06:30" ... ]
958 */
959 var time_fields_arr=[
960 'select[name="rangetime' + resource_id + '"]',
961 'select[name="rangetime' + resource_id + '[]"]',
962 'select[name="starttime' + resource_id + '"]',
963 'select[name="starttime' + resource_id + '[]"]',
964 'select[name="endtime' + resource_id + '"]',
965 'select[name="endtime' + resource_id + '[]"]',
966 'select[name="durationtime' + resource_id + '"]',
967 'select[name="durationtime' + resource_id + '[]"]'
968 ];
969
970 var time_fields_obj_arr = [];
971
972 // Loop all Time Fields
973 for ( var ctf= 0; ctf < time_fields_arr.length; ctf++ ){
974
975 var time_field = time_fields_arr[ ctf ];
976
977 var time_option;
978 if ( is_only_selected_time ){
979 time_option = jQuery( '#booking_form' + resource_id + ' ' + time_field + ' option:selected' ); // Exclude conditional fields, because of using '#booking_form3 ...'
980 } else {
981 time_option = jQuery( '#booking_form' + resource_id + ' ' + time_field + ' option' ); // All time fields
982 }
983
984
985 // Loop all options in time field
986 for ( var j = 0; j < time_option.length; j++ ){
987
988 var jquery_option = jQuery( time_option[ j ] ); // Get only selected options //jQuery( time_field + ' option:eq(' + j + ')' );
989 var value_option_seconds_arr = jquery_option.val().split( '-' );
990 var times_as_seconds = [];
991
992 // Get time as seconds
993 if ( value_option_seconds_arr.length ){ // FixIn: 9.8.10.1.
994 for ( let i = 0; i < value_option_seconds_arr.length; i++ ){ // FixIn: 10.0.0.56.
995 // value_option_seconds_arr[i] = '14:00 ' | ' 16:00' (if from 'rangetime') and '16:00' if (start/end time)
996
997 var start_end_times_arr = value_option_seconds_arr[ i ].trim().split( ':' );
998
999 var time_in_seconds = parseInt( start_end_times_arr[ 0 ] ) * 60 * 60 + parseInt( start_end_times_arr[ 1 ] ) * 60;
1000
1001 times_as_seconds.push( time_in_seconds );
1002 }
1003 }
1004
1005 time_fields_obj_arr.push( {
1006 'name' : jQuery( '#booking_form' + resource_id + ' ' + time_field ).attr( 'name' ),
1007 'value_option_24h': jquery_option.val(),
1008 'jquery_option' : jquery_option,
1009 'times_as_seconds': times_as_seconds
1010 } );
1011 }
1012 }
1013
1014 // Text: [starttime] - [endtime] -----------------------------------------------------------------------------
1015
1016 var text_time_fields_arr=[
1017 'input[name="starttime' + resource_id + '"]',
1018 'input[name="endtime' + resource_id + '"]',
1019 ];
1020 for ( var tf= 0; tf < text_time_fields_arr.length; tf++ ){
1021
1022 var text_jquery = jQuery( '#booking_form' + resource_id + ' ' + text_time_fields_arr[ tf ] ); // Exclude conditional fields, because of using '#booking_form3 ...'
1023 if ( text_jquery.length > 0 ){
1024
1025 var time__h_m__arr = text_jquery.val().trim().split( ':' ); // '14:00'
1026 if ( 0 == time__h_m__arr.length ){
1027 continue; // Not entered time value in a field
1028 }
1029 if ( 1 == time__h_m__arr.length ){
1030 if ( '' === time__h_m__arr[ 0 ] ){
1031 continue; // Not entered time value in a field
1032 }
1033 time__h_m__arr[ 1 ] = 0;
1034 }
1035 var text_time_in_seconds = parseInt( time__h_m__arr[ 0 ] ) * 60 * 60 + parseInt( time__h_m__arr[ 1 ] ) * 60;
1036
1037 var text_times_as_seconds = [];
1038 text_times_as_seconds.push( text_time_in_seconds );
1039
1040 time_fields_obj_arr.push( {
1041 'name' : text_jquery.attr( 'name' ),
1042 'value_option_24h': text_jquery.val(),
1043 'jquery_option' : text_jquery,
1044 'times_as_seconds': text_times_as_seconds
1045 } );
1046 }
1047 }
1048
1049 return time_fields_obj_arr;
1050 }
1051
1052
1053
1054 // ---------------------------------------------------------------------------------------------------------------------
1055 /* == S U P P O R T for C A L E N D A R ==
1056 // --------------------------------------------------------------------------------------------------------------------- */
1057
1058 /**
1059 * Get Calendar datepick Instance
1060 * @param resource_id of booking resource
1061 * @returns {*|null}
1062 */
1063 function wpbc_calendar__get_inst( resource_id ){
1064
1065 if ( 'undefined' === typeof (resource_id) ){
1066 resource_id = '1';
1067 }
1068
1069 if ( jQuery( '#calendar_booking' + resource_id ).length > 0 ){
1070 return jQuery.datepick._getInst( jQuery( '#calendar_booking' + resource_id ).get( 0 ) );
1071 }
1072
1073 return null;
1074 }
1075
1076 /**
1077 * Unselect all dates in calendar and visually update this calendar
1078 *
1079 * @param resource_id ID of booking resource
1080 * @returns {boolean} true on success | false, if no such calendar
1081 */
1082 function wpbc_calendar__unselect_all_dates( resource_id ){
1083
1084 if ( 'undefined' === typeof (resource_id) ){
1085 resource_id = '1';
1086 }
1087
1088 var inst = wpbc_calendar__get_inst( resource_id )
1089
1090 if ( null !== inst ){
1091
1092 // Unselect all dates and set properties of Datepick
1093 jQuery( '#date_booking' + resource_id ).val( '' ); //FixIn: 5.4.3
1094 inst.stayOpen = false;
1095 inst.dates = [];
1096 jQuery.datepick._updateDatepick( inst );
1097
1098 return true
1099 }
1100
1101 return false;
1102
1103 }
1104
1105 /**
1106 * Clear days highlighting in All or specific Calendars
1107 *
1108 * @param resource_id - can be skiped to clear highlighting in all calendars
1109 */
1110 function wpbc_calendars__clear_days_highlighting( resource_id ){
1111
1112 if ( 'undefined' !== typeof ( resource_id ) ){
1113
1114 jQuery( '#calendar_booking' + resource_id + ' .datepick-days-cell-over' ).removeClass( 'datepick-days-cell-over' ); // Clear in specific calendar
1115
1116 } else {
1117 jQuery( '.datepick-days-cell-over' ).removeClass( 'datepick-days-cell-over' ); // Clear in all calendars
1118 }
1119 }
1120
1121 /**
1122 * Scroll to specific month in calendar
1123 *
1124 * @param resource_id ID of resource
1125 * @param year - real year - 2023
1126 * @param month - real month - 12
1127 * @returns {boolean}
1128 */
1129 function wpbc_calendar__scroll_to( resource_id, year, month ){
1130
1131 if ( 'undefined' === typeof (resource_id) ){ resource_id = '1'; }
1132 var inst = wpbc_calendar__get_inst( resource_id )
1133 if ( null !== inst ){
1134
1135 year = parseInt( year );
1136 month = parseInt( month ) - 1; // In JS date, month -1
1137
1138 inst.cursorDate = new Date();
1139 // In some cases, the setFullYear can set only Year, and not the Month and day // FixIn: 6.2.3.5.
1140 inst.cursorDate.setFullYear( year, month, 1 );
1141 inst.cursorDate.setMonth( month );
1142 inst.cursorDate.setDate( 1 );
1143
1144 inst.drawMonth = inst.cursorDate.getMonth();
1145 inst.drawYear = inst.cursorDate.getFullYear();
1146
1147 jQuery.datepick._notifyChange( inst );
1148 jQuery.datepick._adjustInstDate( inst );
1149 jQuery.datepick._showDate( inst );
1150 jQuery.datepick._updateDatepick( inst );
1151
1152 return true;
1153 }
1154 return false;
1155 }
1156
1157 /**
1158 * Is this date selectable in calendar (mainly it's means AVAILABLE date)
1159 *
1160 * @param {int|string} resource_id 1
1161 * @param {string} sql_class_day '2023-08-11'
1162 * @returns {boolean} true | false
1163 */
1164 function wpbc_is_this_day_selectable( resource_id, sql_class_day ){
1165
1166 // Get Data --------------------------------------------------------------------------------------------------------
1167 var date_bookings_obj = _wpbc.bookings_in_calendar__get_for_date( resource_id, sql_class_day );
1168
1169 var is_day_selectable = ( parseInt( date_bookings_obj[ 'day_availability' ] ) > 0 );
1170
1171 if ( typeof (date_bookings_obj[ 'summary' ]) === 'undefined' ){
1172 return is_day_selectable;
1173 }
1174
1175 if ( 'available' != date_bookings_obj[ 'summary']['status_for_day' ] ){
1176
1177 var is_set_pending_days_selectable = _wpbc.calendar__get_param_value( resource_id, 'pending_days_selectable' ); // set pending days selectable // FixIn: 8.6.1.18.
1178
1179 switch ( date_bookings_obj[ 'summary']['status_for_bookings' ] ){
1180 case 'pending':
1181 // Situations for "change-over" days:
1182 case 'pending_pending':
1183 case 'pending_approved':
1184 case 'approved_pending':
1185 is_day_selectable = (is_day_selectable) ? true : is_set_pending_days_selectable;
1186 break;
1187 default:
1188 }
1189 }
1190
1191 return is_day_selectable;
1192 }
1193
1194 /**
1195 * Is date to check IN array of selected dates
1196 *
1197 * @param {date}js_date_to_check - JS Date - simple JavaScript Date object
1198 * @param {[]} js_dates_arr - [ JSDate, ... ] - array of JS dates
1199 * @returns {boolean}
1200 */
1201 function wpbc_is_this_day_among_selected_days( js_date_to_check, js_dates_arr ){
1202
1203 for ( var date_index = 0; date_index < js_dates_arr.length ; date_index++ ){ // FixIn: 8.4.5.16.
1204 if ( ( js_dates_arr[ date_index ].getFullYear() === js_date_to_check.getFullYear() ) &&
1205 ( js_dates_arr[ date_index ].getMonth() === js_date_to_check.getMonth() ) &&
1206 ( js_dates_arr[ date_index ].getDate() === js_date_to_check.getDate() ) ) {
1207 return true;
1208 }
1209 }
1210
1211 return false;
1212 }
1213
1214 /**
1215 * Get SQL Class Date '2023-08-01' from JS Date
1216 *
1217 * @param date JS Date
1218 * @returns {string} '2023-08-12'
1219 */
1220 function wpbc__get__sql_class_date( date ){
1221
1222 var sql_class_day = date.getFullYear() + '-';
1223 sql_class_day += ( ( date.getMonth() + 1 ) < 10 ) ? '0' : '';
1224 sql_class_day += ( date.getMonth() + 1 ) + '-'
1225 sql_class_day += ( date.getDate() < 10 ) ? '0' : '';
1226 sql_class_day += date.getDate();
1227
1228 return sql_class_day;
1229 }
1230
1231 /**
1232 * Get JS Date from the SQL date format '2024-05-14'
1233 * @param sql_class_date
1234 * @returns {Date}
1235 */
1236 function wpbc__get__js_date( sql_class_date ){
1237
1238 var sql_class_date_arr = sql_class_date.split( '-' );
1239
1240 var date_js = new Date();
1241
1242 date_js.setFullYear( parseInt( sql_class_date_arr[ 0 ] ), (parseInt( sql_class_date_arr[ 1 ] ) - 1), parseInt( sql_class_date_arr[ 2 ] ) ); // year, month, date
1243
1244 // Without this time adjust Dates selection in Datepicker can not work!!!
1245 date_js.setHours(0);
1246 date_js.setMinutes(0);
1247 date_js.setSeconds(0);
1248 date_js.setMilliseconds(0);
1249
1250 return date_js;
1251 }
1252
1253 /**
1254 * Get TD Class Date '1-31-2023' from JS Date
1255 *
1256 * @param date JS Date
1257 * @returns {string} '1-31-2023'
1258 */
1259 function wpbc__get__td_class_date( date ){
1260
1261 var td_class_day = (date.getMonth() + 1) + '-' + date.getDate() + '-' + date.getFullYear(); // '1-9-2023'
1262
1263 return td_class_day;
1264 }
1265
1266 /**
1267 * Get date params from string date
1268 *
1269 * @param date string date like '31.5.2023'
1270 * @param separator default '.' can be skipped.
1271 * @returns { {date: number, month: number, year: number} }
1272 */
1273 function wpbc__get__date_params__from_string_date( date , separator){
1274
1275 separator = ( 'undefined' !== typeof (separator) ) ? separator : '.';
1276
1277 var date_arr = date.split( separator );
1278 var date_obj = {
1279 'year' : parseInt( date_arr[ 2 ] ),
1280 'month': (parseInt( date_arr[ 1 ] ) - 1),
1281 'date' : parseInt( date_arr[ 0 ] )
1282 };
1283 return date_obj; // for = new Date( date_obj.year , date_obj.month , date_obj.date );
1284 }
1285
1286 /**
1287 * Add Spin Loader to calendar
1288 * @param resource_id
1289 */
1290 function wpbc_calendar__loading__start( resource_id ){
1291 if ( ! jQuery( '#calendar_booking' + resource_id ).next().hasClass( 'wpbc_spins_loader_wrapper' ) ){
1292 jQuery( '#calendar_booking' + resource_id ).after( '<div class="wpbc_spins_loader_wrapper"><div class="wpbc_spins_loader"></div></div>' );
1293 }
1294 if ( ! jQuery( '#calendar_booking' + resource_id ).hasClass( 'wpbc_calendar_blur_small' ) ){
1295 jQuery( '#calendar_booking' + resource_id ).addClass( 'wpbc_calendar_blur_small' );
1296 }
1297 wpbc_calendar__blur__start( resource_id );
1298 }
1299
1300 /**
1301 * Remove Spin Loader to calendar
1302 * @param resource_id
1303 */
1304 function wpbc_calendar__loading__stop( resource_id ){
1305 jQuery( '#calendar_booking' + resource_id + ' + .wpbc_spins_loader_wrapper' ).remove();
1306 jQuery( '#calendar_booking' + resource_id ).removeClass( 'wpbc_calendar_blur_small' );
1307 wpbc_calendar__blur__stop( resource_id );
1308 }
1309
1310 /**
1311 * Add Blur to calendar
1312 * @param resource_id
1313 */
1314 function wpbc_calendar__blur__start( resource_id ){
1315 if ( ! jQuery( '#calendar_booking' + resource_id ).hasClass( 'wpbc_calendar_blur' ) ){
1316 jQuery( '#calendar_booking' + resource_id ).addClass( 'wpbc_calendar_blur' );
1317 }
1318 }
1319
1320 /**
1321 * Remove Blur in calendar
1322 * @param resource_id
1323 */
1324 function wpbc_calendar__blur__stop( resource_id ){
1325 jQuery( '#calendar_booking' + resource_id ).removeClass( 'wpbc_calendar_blur' );
1326 }
1327
1328
1329 // .................................................................................................................
1330 /* == Calendar Update - View ==
1331 // ................................................................................................................. */
1332
1333 /**
1334 * Update Look of calendar
1335 *
1336 * @param resource_id
1337 */
1338 function wpbc_calendar__update_look( resource_id ){
1339
1340 var inst = wpbc_calendar__get_inst( resource_id );
1341
1342 jQuery.datepick._updateDatepick( inst );
1343 }
1344
1345
1346 /**
1347 * Update dynamically Number of Months in calendar
1348 *
1349 * @param resource_id int
1350 * @param months_number int
1351 */
1352 function wpbc_calendar__update_months_number( resource_id, months_number ){
1353 var inst = wpbc_calendar__get_inst( resource_id );
1354 if ( null !== inst ){
1355 inst.settings[ 'numberOfMonths' ] = months_number;
1356 //_wpbc.calendar__set_param_value( resource_id, 'calendar_number_of_months', months_number );
1357 wpbc_calendar__update_look( resource_id );
1358 }
1359 }
1360
1361
1362 /**
1363 * Show calendar in different Skin
1364 *
1365 * @param selected_skin_url
1366 */
1367 function wpbc__calendar__change_skin( selected_skin_url ){
1368
1369 //console.log( 'SKIN SELECTION ::', selected_skin_url );
1370
1371 // Remove CSS skin
1372 var stylesheet = document.getElementById( 'wpbc-calendar-skin-css' );
1373 stylesheet.parentNode.removeChild( stylesheet );
1374
1375
1376 // Add new CSS skin
1377 var headID = document.getElementsByTagName( "head" )[ 0 ];
1378 var cssNode = document.createElement( 'link' );
1379 cssNode.type = 'text/css';
1380 cssNode.setAttribute( "id", "wpbc-calendar-skin-css" );
1381 cssNode.rel = 'stylesheet';
1382 cssNode.media = 'screen';
1383 cssNode.href = selected_skin_url; //"http://beta/wp-content/plugins/booking/css/skins/green-01.css";
1384 headID.appendChild( cssNode );
1385 }
1386
1387
1388 function wpbc__css__change_skin( selected_skin_url, stylesheet_id = 'wpbc-time_picker-skin-css' ){
1389
1390 // Remove CSS skin
1391 var stylesheet = document.getElementById( stylesheet_id );
1392 stylesheet.parentNode.removeChild( stylesheet );
1393
1394
1395 // Add new CSS skin
1396 var headID = document.getElementsByTagName( "head" )[ 0 ];
1397 var cssNode = document.createElement( 'link' );
1398 cssNode.type = 'text/css';
1399 cssNode.setAttribute( "id", stylesheet_id );
1400 cssNode.rel = 'stylesheet';
1401 cssNode.media = 'screen';
1402 cssNode.href = selected_skin_url; //"http://beta/wp-content/plugins/booking/css/skins/green-01.css";
1403 headID.appendChild( cssNode );
1404 }
1405
1406
1407 // ---------------------------------------------------------------------------------------------------------------------
1408 /* == S U P P O R T M A T H ==
1409 // --------------------------------------------------------------------------------------------------------------------- */
1410
1411 /**
1412 * Merge several intersected intervals or return not intersected: [[1,3],[2,6],[8,10],[15,18]] -> [[1,6],[8,10],[15,18]]
1413 *
1414 * @param [] intervals [ [1,3],[2,4],[6,8],[9,10],[3,7] ]
1415 * @returns [] [ [1,8],[9,10] ]
1416 *
1417 * Exmample: wpbc_intervals__merge_inersected( [ [1,3],[2,4],[6,8],[9,10],[3,7] ] );
1418 */
1419 function wpbc_intervals__merge_inersected( intervals ){
1420
1421 if ( ! intervals || intervals.length === 0 ){
1422 return [];
1423 }
1424
1425 var merged = [];
1426 intervals.sort( function ( a, b ){
1427 return a[ 0 ] - b[ 0 ];
1428 } );
1429
1430 var mergedInterval = intervals[ 0 ];
1431
1432 for ( var i = 1; i < intervals.length; i++ ){
1433 var interval = intervals[ i ];
1434
1435 if ( interval[ 0 ] <= mergedInterval[ 1 ] ){
1436 mergedInterval[ 1 ] = Math.max( mergedInterval[ 1 ], interval[ 1 ] );
1437 } else {
1438 merged.push( mergedInterval );
1439 mergedInterval = interval;
1440 }
1441 }
1442
1443 merged.push( mergedInterval );
1444 return merged;
1445 }
1446
1447
1448 /**
1449 * Is 2 intervals intersected: [36011, 86392] <=> [1, 43192] => true ( intersected )
1450 *
1451 * Good explanation here https://stackoverflow.com/questions/3269434/whats-the-most-efficient-way-to-test-if-two-ranges-overlap
1452 *
1453 * @param interval_A - [ 36011, 86392 ]
1454 * @param interval_B - [ 1, 43192 ]
1455 *
1456 * @return bool
1457 */
1458 function wpbc_intervals__is_intersected( interval_A, interval_B ) {
1459
1460 if (
1461 ( 0 == interval_A.length )
1462 || ( 0 == interval_B.length )
1463 ){
1464 return false;
1465 }
1466
1467 interval_A[ 0 ] = parseInt( interval_A[ 0 ] );
1468 interval_A[ 1 ] = parseInt( interval_A[ 1 ] );
1469 interval_B[ 0 ] = parseInt( interval_B[ 0 ] );
1470 interval_B[ 1 ] = parseInt( interval_B[ 1 ] );
1471
1472 var is_intersected = Math.max( interval_A[ 0 ], interval_B[ 0 ] ) - Math.min( interval_A[ 1 ], interval_B[ 1 ] );
1473
1474 // if ( 0 == is_intersected ) {
1475 // // Such ranges going one after other, e.g.: [ 12, 15 ] and [ 15, 21 ]
1476 // }
1477
1478 if ( is_intersected < 0 ) {
1479 return true; // INTERSECTED
1480 }
1481
1482 return false; // Not intersected
1483 }
1484
1485
1486 /**
1487 * Get the closets ABS value of element in array to the current myValue
1488 *
1489 * @param myValue - int element to search closet 4
1490 * @param myArray - array of elements where to search [5,8,1,7]
1491 * @returns int 5
1492 */
1493 function wpbc_get_abs_closest_value_in_arr( myValue, myArray ){
1494
1495 if ( myArray.length == 0 ){ // If the array is empty -> return the myValue
1496 return myValue;
1497 }
1498
1499 var obj = myArray[ 0 ];
1500 var diff = Math.abs( myValue - obj ); // Get distance between 1st element
1501 var closetValue = myArray[ 0 ]; // Save 1st element
1502
1503 for ( var i = 1; i < myArray.length; i++ ){
1504 obj = myArray[ i ];
1505
1506 if ( Math.abs( myValue - obj ) < diff ){ // we found closer value -> save it
1507 diff = Math.abs( myValue - obj );
1508 closetValue = obj;
1509 }
1510 }
1511
1512 return closetValue;
1513 }
1514
1515
1516 // ---------------------------------------------------------------------------------------------------------------------
1517 /* == T O O L T I P S ==
1518 // --------------------------------------------------------------------------------------------------------------------- */
1519
1520 /**
1521 * Define tooltip to show, when mouse over Date in Calendar
1522 *
1523 * @param tooltip_text - Text to show 'Booked time: 12:00 - 13:00<br>Cost: $20.00'
1524 * @param resource_id - ID of booking resource '1'
1525 * @param td_class - SQL class '1-9-2023'
1526 * @returns {boolean} - defined to show or not
1527 */
1528 function wpbc_set_tooltip___for__calendar_date( tooltip_text, resource_id, td_class ){
1529
1530 //TODO: make escaping of text for quot symbols, and JS/HTML...
1531
1532 jQuery( '#calendar_booking' + resource_id + ' td.cal4date-' + td_class ).attr( 'data-content', tooltip_text );
1533
1534 var td_el = jQuery( '#calendar_booking' + resource_id + ' td.cal4date-' + td_class ).get( 0 ); // FixIn: 9.0.1.1.
1535
1536 if (
1537 ( 'undefined' !== typeof(td_el) )
1538 && ( undefined == td_el._tippy )
1539 && ( '' !== tooltip_text )
1540 ){
1541
1542 wpbc_tippy( td_el , {
1543 content( reference ){
1544
1545 var popover_content = reference.getAttribute( 'data-content' );
1546
1547 return '<div class="popover popover_tippy">'
1548 + '<div class="popover-content">'
1549 + popover_content
1550 + '</div>'
1551 + '</div>';
1552 },
1553 allowHTML : true,
1554 trigger : 'mouseenter focus',
1555 interactive : false,
1556 hideOnClick : true,
1557 interactiveBorder: 10,
1558 maxWidth : 550,
1559 theme : 'wpbc-tippy-times',
1560 placement : 'top',
1561 delay : [400, 0], // FixIn: 9.4.2.2.
1562 //delay : [0, 9999999999], // Debuge tooltip
1563 ignoreAttributes : true,
1564 touch : true, //['hold', 500], // 500ms delay // FixIn: 9.2.1.5.
1565 appendTo: () => document.body,
1566 });
1567
1568 return true;
1569 }
1570
1571 return false;
1572 }
1573
1574
1575 // ---------------------------------------------------------------------------------------------------------------------
1576 /* == Dates Functions ==
1577 // --------------------------------------------------------------------------------------------------------------------- */
1578
1579 /**
1580 * Get number of dates between 2 JS Dates
1581 *
1582 * @param date1 JS Date
1583 * @param date2 JS Date
1584 * @returns {number}
1585 */
1586 function wpbc_dates__days_between(date1, date2) {
1587
1588 // The number of milliseconds in one day
1589 var ONE_DAY = 1000 * 60 * 60 * 24;
1590
1591 // Convert both dates to milliseconds
1592 var date1_ms = date1.getTime();
1593 var date2_ms = date2.getTime();
1594
1595 // Calculate the difference in milliseconds
1596 var difference_ms = date1_ms - date2_ms;
1597
1598 // Convert back to days and return
1599 return Math.round(difference_ms/ONE_DAY);
1600 }
1601
1602
1603 /**
1604 * Check if this array of dates is consecutive array of dates or not.
1605 * e.g. ['2024-05-09','2024-05-19','2024-05-30'] -> false
1606 * e.g. ['2024-05-09','2024-05-10','2024-05-11'] -> true
1607 * @param sql_dates_arr array e.g.: ['2024-05-09','2024-05-19','2024-05-30']
1608 * @returns {boolean}
1609 */
1610 function wpbc_dates__is_consecutive_dates_arr_range( sql_dates_arr ){ // FixIn: 10.0.0.50.
1611
1612 if ( sql_dates_arr.length > 1 ){
1613 var previos_date = wpbc__get__js_date( sql_dates_arr[ 0 ] );
1614 var current_date;
1615
1616 for ( var i = 1; i < sql_dates_arr.length; i++ ){
1617 current_date = wpbc__get__js_date( sql_dates_arr[i] );
1618
1619 if ( wpbc_dates__days_between( current_date, previos_date ) != 1 ){
1620 return false;
1621 }
1622
1623 previos_date = current_date;
1624 }
1625 }
1626
1627 return true;
1628 }
1629
1630
1631 // ---------------------------------------------------------------------------------------------------------------------
1632 /* == Auto Dates Selection ==
1633 // --------------------------------------------------------------------------------------------------------------------- */
1634
1635 /**
1636 * == How to use ? ==
1637 *
1638 * For Dates selection, we need to use this logic! We need select the dates only after booking data loaded!
1639 *
1640 * Check example bellow.
1641 *
1642 * // Fire on all booking dates loaded
1643 * jQuery( 'body' ).on( 'wpbc_calendar_ajx__loaded_data', function ( event, loaded_resource_id ){
1644 *
1645 * if ( loaded_resource_id == select_dates_in_calendar_id ){
1646 * wpbc_auto_select_dates_in_calendar( select_dates_in_calendar_id, '2024-05-15', '2024-05-25' );
1647 * }
1648 * } );
1649 *
1650 */
1651
1652
1653 /**
1654 * Try to Auto select dates in specific calendar by simulated clicks in datepicker
1655 *
1656 * @param resource_id 1
1657 * @param check_in_ymd '2024-05-09' OR ['2024-05-09','2024-05-19','2024-05-20']
1658 * @param check_out_ymd '2024-05-15' Optional
1659 *
1660 * @returns {number} number of selected dates
1661 *
1662 * Example 1: var num_selected_days = wpbc_auto_select_dates_in_calendar( 1, '2024-05-15', '2024-05-25' );
1663 * Example 2: var num_selected_days = wpbc_auto_select_dates_in_calendar( 1, ['2024-05-09','2024-05-19','2024-05-20'] );
1664 */
1665 function wpbc_auto_select_dates_in_calendar( resource_id, check_in_ymd, check_out_ymd = '' ){ // FixIn: 10.0.0.47.
1666
1667 console.log( 'WPBC_AUTO_SELECT_DATES_IN_CALENDAR( RESOURCE_ID, CHECK_IN_YMD, CHECK_OUT_YMD )', resource_id, check_in_ymd, check_out_ymd );
1668
1669 if (
1670 ( '2100-01-01' == check_in_ymd )
1671 || ( '2100-01-01' == check_out_ymd )
1672 || ( ( '' == check_in_ymd ) && ( '' == check_out_ymd ) )
1673 ){
1674 return 0;
1675 }
1676
1677 // -----------------------------------------------------------------------------------------------------------------
1678 // If check_in_ymd = [ '2024-05-09','2024-05-19','2024-05-30' ] ARRAY of DATES // FixIn: 10.0.0.50.
1679 // -----------------------------------------------------------------------------------------------------------------
1680 var dates_to_select_arr = [];
1681 if ( Array.isArray( check_in_ymd ) ){
1682 dates_to_select_arr = wpbc_clone_obj( check_in_ymd );
1683
1684 // -------------------------------------------------------------------------------------------------------------
1685 // Exceptions to set MULTIPLE DAYS mode
1686 // -------------------------------------------------------------------------------------------------------------
1687 // if dates as NOT CONSECUTIVE: ['2024-05-09','2024-05-19','2024-05-30'], -> set MULTIPLE DAYS mode
1688 if (
1689 ( dates_to_select_arr.length > 0 )
1690 && ( '' == check_out_ymd )
1691 && ( ! wpbc_dates__is_consecutive_dates_arr_range( dates_to_select_arr ) )
1692 ){
1693 wpbc_cal_days_select__multiple( resource_id );
1694 }
1695 // if multiple days to select, but enabled SINGLE day mode, -> set MULTIPLE DAYS mode
1696 if (
1697 ( dates_to_select_arr.length > 1 )
1698 && ( '' == check_out_ymd )
1699 && ( 'single' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ) )
1700 ){
1701 wpbc_cal_days_select__multiple( resource_id );
1702 }
1703 // -------------------------------------------------------------------------------------------------------------
1704 check_in_ymd = dates_to_select_arr[ 0 ];
1705 if ( '' == check_out_ymd ){
1706 check_out_ymd = dates_to_select_arr[ (dates_to_select_arr.length-1) ];
1707 }
1708 }
1709 // -----------------------------------------------------------------------------------------------------------------
1710
1711
1712 if ( '' == check_in_ymd ){
1713 check_in_ymd = check_out_ymd;
1714 }
1715 if ( '' == check_out_ymd ){
1716 check_out_ymd = check_in_ymd;
1717 }
1718
1719 if ( 'undefined' === typeof (resource_id) ){
1720 resource_id = '1';
1721 }
1722
1723
1724 var inst = wpbc_calendar__get_inst( resource_id );
1725
1726 if ( null !== inst ){
1727
1728 // Unselect all dates and set properties of Datepick
1729 jQuery( '#date_booking' + resource_id ).val( '' ); //FixIn: 5.4.3
1730 inst.stayOpen = false;
1731 inst.dates = [];
1732 var check_in_js = wpbc__get__js_date( check_in_ymd );
1733 var td_cell = wpbc_get_clicked_td( inst.id, check_in_js );
1734
1735 // Is ome type of error, then select multiple days selection mode.
1736 if ( '' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ) ) {
1737 _wpbc.calendar__set_param_value( resource_id, 'days_select_mode', 'multiple' );
1738 }
1739
1740
1741 // ---------------------------------------------------------------------------------------------------------
1742 // == DYNAMIC ==
1743 if ( 'dynamic' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ) ){
1744 // 1-st click
1745 inst.stayOpen = false;
1746 jQuery.datepick._selectDay( td_cell, '#' + inst.id, check_in_js.getTime() );
1747 if ( 0 === inst.dates.length ){
1748 return 0; // First click was unsuccessful, so we must not make other click
1749 }
1750
1751 // 2-nd click
1752 var check_out_js = wpbc__get__js_date( check_out_ymd );
1753 var td_cell_out = wpbc_get_clicked_td( inst.id, check_out_js );
1754 inst.stayOpen = true;
1755 jQuery.datepick._selectDay( td_cell_out, '#' + inst.id, check_out_js.getTime() );
1756 }
1757
1758 // ---------------------------------------------------------------------------------------------------------
1759 // == FIXED ==
1760 if ( 'fixed' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' )) {
1761 jQuery.datepick._selectDay( td_cell, '#' + inst.id, check_in_js.getTime() );
1762 }
1763
1764 // ---------------------------------------------------------------------------------------------------------
1765 // == SINGLE ==
1766 if ( 'single' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ) ){
1767 //jQuery.datepick._restrictMinMax( inst, jQuery.datepick._determineDate( inst, check_in_js, null ) ); // Do we need to run this ? Please note, check_in_js must have time, min, sec defined to 0!
1768 jQuery.datepick._selectDay( td_cell, '#' + inst.id, check_in_js.getTime() );
1769 }
1770
1771 // ---------------------------------------------------------------------------------------------------------
1772 // == MULTIPLE ==
1773 if ( 'multiple' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ) ){
1774
1775 var dates_arr;
1776
1777 if ( dates_to_select_arr.length > 0 ){
1778 // Situation, when we have dates array: ['2024-05-09','2024-05-19','2024-05-30']. and not the Check In / Check out dates as parameter in this function
1779 dates_arr = wpbc_get_selection_dates_js_str_arr__from_arr( dates_to_select_arr );
1780 } else {
1781 dates_arr = wpbc_get_selection_dates_js_str_arr__from_check_in_out( check_in_ymd, check_out_ymd, inst );
1782 }
1783
1784 if ( 0 === dates_arr.dates_js.length ){
1785 return 0;
1786 }
1787
1788 // For Calendar Days selection
1789 for ( var j = 0; j < dates_arr.dates_js.length; j++ ){ // Loop array of dates
1790
1791 var str_date = wpbc__get__sql_class_date( dates_arr.dates_js[ j ] );
1792
1793 // Date unavailable !
1794 if ( 0 == _wpbc.bookings_in_calendar__get_for_date( resource_id, str_date ).day_availability ){
1795 return 0;
1796 }
1797
1798 if ( dates_arr.dates_js[ j ] != -1 ) {
1799 inst.dates.push( dates_arr.dates_js[ j ] );
1800 }
1801 }
1802
1803 var check_out_date = dates_arr.dates_js[ (dates_arr.dates_js.length - 1) ];
1804
1805 inst.dates.push( check_out_date ); // Need add one additional SAME date for correct works of dates selection !!!!!
1806
1807 var checkout_timestamp = check_out_date.getTime();
1808 var td_cell = wpbc_get_clicked_td( inst.id, check_out_date );
1809
1810 jQuery.datepick._selectDay( td_cell, '#' + inst.id, checkout_timestamp );
1811 }
1812
1813
1814 if ( 0 !== inst.dates.length ){
1815 // Scroll to specific month, if we set dates in some future months
1816 wpbc_calendar__scroll_to( resource_id, inst.dates[ 0 ].getFullYear(), inst.dates[ 0 ].getMonth()+1 );
1817 }
1818
1819 return inst.dates.length;
1820 }
1821
1822 return 0;
1823 }
1824
1825 /**
1826 * Get HTML td element (where was click in calendar day cell)
1827 *
1828 * @param calendar_html_id 'calendar_booking1'
1829 * @param date_js JS Date
1830 * @returns {*|jQuery} Dom HTML td element
1831 */
1832 function wpbc_get_clicked_td( calendar_html_id, date_js ){
1833
1834 var td_cell = jQuery( '#' + calendar_html_id + ' .sql_date_' + wpbc__get__sql_class_date( date_js ) ).get( 0 );
1835
1836 return td_cell;
1837 }
1838
1839 /**
1840 * Get arrays of JS and SQL dates as dates array
1841 *
1842 * @param check_in_ymd '2024-05-15'
1843 * @param check_out_ymd '2024-05-25'
1844 * @param inst Datepick Inst. Use wpbc_calendar__get_inst( resource_id );
1845 * @returns {{dates_js: *[], dates_str: *[]}}
1846 */
1847 function wpbc_get_selection_dates_js_str_arr__from_check_in_out( check_in_ymd, check_out_ymd , inst ){
1848
1849 var original_array = [];
1850 var date;
1851 var bk_distinct_dates = [];
1852
1853 var check_in_date = check_in_ymd.split( '-' );
1854 var check_out_date = check_out_ymd.split( '-' );
1855
1856 date = new Date();
1857 date.setFullYear( check_in_date[ 0 ], (check_in_date[ 1 ] - 1), check_in_date[ 2 ] ); // year, month, date
1858 var original_check_in_date = date;
1859 original_array.push( jQuery.datepick._restrictMinMax( inst, jQuery.datepick._determineDate( inst, date, null ) ) ); //add date
1860 if ( ! wpbc_in_array( bk_distinct_dates, (check_in_date[ 2 ] + '.' + check_in_date[ 1 ] + '.' + check_in_date[ 0 ]) ) ){
1861 bk_distinct_dates.push( parseInt(check_in_date[ 2 ]) + '.' + parseInt(check_in_date[ 1 ]) + '.' + check_in_date[ 0 ] );
1862 }
1863
1864 var date_out = new Date();
1865 date_out.setFullYear( check_out_date[ 0 ], (check_out_date[ 1 ] - 1), check_out_date[ 2 ] ); // year, month, date
1866 var original_check_out_date = date_out;
1867
1868 var mewDate = new Date( original_check_in_date.getFullYear(), original_check_in_date.getMonth(), original_check_in_date.getDate() );
1869 mewDate.setDate( original_check_in_date.getDate() + 1 );
1870
1871 while (
1872 (original_check_out_date > date) &&
1873 (original_check_in_date != original_check_out_date) ){
1874 date = new Date( mewDate.getFullYear(), mewDate.getMonth(), mewDate.getDate() );
1875
1876 original_array.push( jQuery.datepick._restrictMinMax( inst, jQuery.datepick._determineDate( inst, date, null ) ) ); //add date
1877 if ( !wpbc_in_array( bk_distinct_dates, (date.getDate() + '.' + parseInt( date.getMonth() + 1 ) + '.' + date.getFullYear()) ) ){
1878 bk_distinct_dates.push( (parseInt(date.getDate()) + '.' + parseInt( date.getMonth() + 1 ) + '.' + date.getFullYear()) );
1879 }
1880
1881 mewDate = new Date( date.getFullYear(), date.getMonth(), date.getDate() );
1882 mewDate.setDate( mewDate.getDate() + 1 );
1883 }
1884 original_array.pop();
1885 bk_distinct_dates.pop();
1886
1887 return {'dates_js': original_array, 'dates_str': bk_distinct_dates};
1888 }
1889
1890 /**
1891 * Get arrays of JS and SQL dates as dates array
1892 *
1893 * @param dates_to_select_arr = ['2024-05-09','2024-05-19','2024-05-30']
1894 *
1895 * @returns {{dates_js: *[], dates_str: *[]}}
1896 */
1897 function wpbc_get_selection_dates_js_str_arr__from_arr( dates_to_select_arr ){ // FixIn: 10.0.0.50.
1898
1899 var original_array = [];
1900 var bk_distinct_dates = [];
1901 var one_date_str;
1902
1903 for ( var d = 0; d < dates_to_select_arr.length; d++ ){
1904
1905 original_array.push( wpbc__get__js_date( dates_to_select_arr[ d ] ) );
1906
1907 one_date_str = dates_to_select_arr[ d ].split('-')
1908 if ( ! wpbc_in_array( bk_distinct_dates, (one_date_str[ 2 ] + '.' + one_date_str[ 1 ] + '.' + one_date_str[ 0 ]) ) ){
1909 bk_distinct_dates.push( parseInt(one_date_str[ 2 ]) + '.' + parseInt(one_date_str[ 1 ]) + '.' + one_date_str[ 0 ] );
1910 }
1911 }
1912
1913 return {'dates_js': original_array, 'dates_str': original_array};
1914 }
1915
1916 // =====================================================================================================================
1917 /* == Auto Fill Fields / Auto Select Dates ==
1918 // ===================================================================================================================== */
1919
1920 jQuery( document ).ready( function (){
1921
1922 var url_params = new URLSearchParams( window.location.search );
1923
1924 // Disable days selection in calendar, after redirection from the "Search results page, after search availability" // FixIn: 8.8.2.3.
1925 if ( 'On' != _wpbc.get_other_param( 'is_enabled_booking_search_results_days_select' ) ) {
1926 if (
1927 ( url_params.has( 'wpbc_select_check_in' ) ) &&
1928 ( url_params.has( 'wpbc_select_check_out' ) ) &&
1929 ( url_params.has( 'wpbc_select_calendar_id' ) )
1930 ){
1931
1932 var select_dates_in_calendar_id = parseInt( url_params.get( 'wpbc_select_calendar_id' ) );
1933
1934 // Fire on all booking dates loaded
1935 jQuery( 'body' ).on( 'wpbc_calendar_ajx__loaded_data', function ( event, loaded_resource_id ){
1936
1937 if ( loaded_resource_id == select_dates_in_calendar_id ){
1938 wpbc_auto_select_dates_in_calendar( select_dates_in_calendar_id, url_params.get( 'wpbc_select_check_in' ), url_params.get( 'wpbc_select_check_out' ) );
1939 }
1940 } );
1941 }
1942 }
1943
1944 if ( url_params.has( 'wpbc_auto_fill' ) ){
1945
1946 var wpbc_auto_fill_value = url_params.get( 'wpbc_auto_fill' );
1947
1948 // Convert back. Some systems do not like symbol '~' in URL, so we need to replace to some other symbols
1949 wpbc_auto_fill_value = wpbc_auto_fill_value.replaceAll( '_^_', '~' );
1950
1951 wpbc_auto_fill_booking_fields( wpbc_auto_fill_value );
1952 }
1953
1954 } );
1955
1956 /**
1957 * Autofill / select booking form fields by values from the GET request parameter: ?wpbc_auto_fill=
1958 *
1959 * @param auto_fill_str
1960 */
1961 function wpbc_auto_fill_booking_fields( auto_fill_str ){ // FixIn: 10.0.0.48.
1962
1963 if ( '' == auto_fill_str ){
1964 return;
1965 }
1966
1967 // console.log( 'WPBC_AUTO_FILL_BOOKING_FIELDS( AUTO_FILL_STR )', auto_fill_str);
1968
1969 var fields_arr = wpbc_auto_fill_booking_fields__parse( auto_fill_str );
1970
1971 for ( let i = 0; i < fields_arr.length; i++ ){
1972 jQuery( '[name="' + fields_arr[ i ][ 'name' ] + '"]' ).val( fields_arr[ i ][ 'value' ] );
1973 }
1974 }
1975
1976 /**
1977 * Parse data from get parameter: ?wpbc_auto_fill=visitors231^2~max_capacity231^2
1978 *
1979 * @param data_str = 'visitors231^2~max_capacity231^2';
1980 * @returns {*}
1981 */
1982 function wpbc_auto_fill_booking_fields__parse( data_str ){
1983
1984 var filter_options_arr = [];
1985
1986 var data_arr = data_str.split( '~' );
1987
1988 for ( var j = 0; j < data_arr.length; j++ ){
1989
1990 var my_form_field = data_arr[ j ].split( '^' );
1991
1992 var filter_name = ('undefined' !== typeof (my_form_field[ 0 ])) ? my_form_field[ 0 ] : '';
1993 var filter_value = ('undefined' !== typeof (my_form_field[ 1 ])) ? my_form_field[ 1 ] : '';
1994
1995 filter_options_arr.push(
1996 {
1997 'name' : filter_name,
1998 'value' : filter_value
1999 }
2000 );
2001 }
2002 return filter_options_arr;
2003 }
2004
2005 /**
2006 * Parse data from get parameter: ?search_get__custom_params=...
2007 *
2008 * @param data_str = 'text^search_field__display_check_in^23.05.2024~text^search_field__display_check_out^26.05.2024~selectbox-one^search_quantity^2~selectbox-one^location^Spain~selectbox-one^max_capacity^2~selectbox-one^amenity^parking~checkbox^search_field__extend_search_days^5~submit^^Search~hidden^search_get__check_in_ymd^2024-05-23~hidden^search_get__check_out_ymd^2024-05-26~hidden^search_get__time^~hidden^search_get__quantity^2~hidden^search_get__extend^5~hidden^search_get__users_id^~hidden^search_get__custom_params^~';
2009 * @returns {*}
2010 */
2011 function wpbc_auto_fill_search_fields__parse( data_str ){
2012
2013 var filter_options_arr = [];
2014
2015 var data_arr = data_str.split( '~' );
2016
2017 for ( var j = 0; j < data_arr.length; j++ ){
2018
2019 var my_form_field = data_arr[ j ].split( '^' );
2020
2021 var filter_type = ('undefined' !== typeof (my_form_field[ 0 ])) ? my_form_field[ 0 ] : '';
2022 var filter_name = ('undefined' !== typeof (my_form_field[ 1 ])) ? my_form_field[ 1 ] : '';
2023 var filter_value = ('undefined' !== typeof (my_form_field[ 2 ])) ? my_form_field[ 2 ] : '';
2024
2025 filter_options_arr.push(
2026 {
2027 'type' : filter_type,
2028 'name' : filter_name,
2029 'value' : filter_value
2030 }
2031 );
2032 }
2033 return filter_options_arr;
2034 }
2035
2036
2037 // ---------------------------------------------------------------------------------------------------------------------
2038 /* == Auto Update number of months in calendars ON screen size changed ==
2039 // --------------------------------------------------------------------------------------------------------------------- */
2040
2041 /**
2042 * Auto Update Number of Months in Calendar, e.g.: if ( WINDOW_WIDTH <= 782px ) >>> MONTHS_NUMBER = 1
2043 * ELSE: number of months defined in shortcode.
2044 * @param resource_id int
2045 *
2046 */
2047 function wpbc_calendar__auto_update_months_number__on_resize( resource_id ){
2048
2049 if ( true === _wpbc.get_other_param( 'is_allow_several_months_on_mobile' ) ) {
2050 return false;
2051 }
2052
2053 var local__number_of_months = parseInt( _wpbc.calendar__get_param_value( resource_id, 'calendar_number_of_months' ) );
2054
2055 if ( local__number_of_months > 1 ){
2056
2057 if ( jQuery( window ).width() <= 782 ){
2058 wpbc_calendar__update_months_number( resource_id, 1 );
2059 } else {
2060 wpbc_calendar__update_months_number( resource_id, local__number_of_months );
2061 }
2062
2063 }
2064 }
2065
2066 /**
2067 * Auto Update Number of Months in ALL Calendars
2068 *
2069 */
2070 function wpbc_calendars__auto_update_months_number(){
2071
2072 var all_calendars_arr = _wpbc.calendars_all__get();
2073
2074 // This LOOP "for in" is GOOD, because we check here keys 'calendar_' === calendar_id.slice( 0, 9 )
2075 for ( var calendar_id in all_calendars_arr ){
2076 if ( 'calendar_' === calendar_id.slice( 0, 9 ) ){
2077 var resource_id = parseInt( calendar_id.slice( 9 ) ); // 'calendar_3' -> 3
2078 if ( resource_id > 0 ){
2079 wpbc_calendar__auto_update_months_number__on_resize( resource_id );
2080 }
2081 }
2082 }
2083 }
2084
2085 /**
2086 * If browser window changed, then update number of months.
2087 */
2088 jQuery( window ).on( 'resize', function (){
2089 wpbc_calendars__auto_update_months_number();
2090 } );
2091
2092 /**
2093 * Auto update calendar number of months on initial page load
2094 */
2095 jQuery( document ).ready( function (){
2096 var closed_timer = setTimeout( function (){
2097 wpbc_calendars__auto_update_months_number();
2098 }, 100 );
2099 });