PluginProbe
Booking Calendar / 11.3
Booking Calendar v11.3
11.9 11.8.4 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 All 205 releases
booking / includes / __js / client / cal / wpbc_cal.js

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

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