PluginProbe
Booking Calendar / 11.1
Booking Calendar v11.1
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 10.11 All 204 releases
booking / includes / __js / client / cal / wpbc_cal.js

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

2,324 lines 89.6 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
541 if ( ( is_unselectable_calendar ) && ( ! is_booking_form_exist ) ){
542
543 /**
544 * Un Hover all dates in calendar (without the booking form), if only Availability Calendar here and we do
545 * not insert Booking form by mistake.
546 */
547
548 wpbc_calendars__clear_days_highlighting( resource_id ); // Clear days highlighting
549
550 var css_of_calendar = '.wpbc_only_calendar #calendar_booking' + resource_id;
551 jQuery( css_of_calendar + ' .datepick-days-cell, '
552 + css_of_calendar + ' .datepick-days-cell a' ).css( 'cursor', 'default' ); // Set cursor to Default
553 return false;
554 }
555
556
557
558 // D a y s H o v e r i n g ------------------------------------------------------------------------------------
559 if (
560 ( location.href.indexOf( 'page=wpbc' ) == -1 )
561 || ( ( location.href.indexOf( 'page=wpbc' ) > 0 ) && ( location.href.indexOf( 'tab=add-booking' ) > 0 ) )
562 || ( is_add_booking_modal_calendar )
563 || ( location.href.indexOf( 'page=wpbc-setup' ) > 0 )
564 || ( location.href.indexOf( 'page=wpbc-availability' ) > 0 )
565 || ( ( location.href.indexOf( 'page=wpbc-settings' ) > 0 ) &&
566 ( location.href.indexOf( '&tab=form' ) > 0 )
567 )
568 ){
569 // The same as dates selection, but for days hovering
570
571 if ( 'function' == typeof( wpbc__calendar__do_days_highlight__bs ) ){
572 wpbc__calendar__do_days_highlight__bs( sql_class_day, date, resource_id );
573 }
574 }
575
576 }
577
578
579 /**
580 * Select calendar date cells
581 *
582 * @param date - JavaScript Date Obj: Mon Dec 11 2023 00:00:00
583 * GMT+0200 (Eastern European Standard Time)
584 * @param calendar_params_arr - Calendar Settings Object: {
585 * "resource_id": 4
586 * }
587 * @param datepick_this - this of datepick Obj
588 *
589 */
590 function wpbc__calendar__on_select_days( date, calendar_params_arr, datepick_this ){
591
592 var resource_id = ( 'undefined' !== typeof(calendar_params_arr[ 'resource_id' ]) ) ? calendar_params_arr[ 'resource_id' ] : '1'; // '1'
593
594 // Set unselectable, if only Availability Calendar here (and we do not insert Booking form by mistake).
595 var is_unselectable_calendar = ( jQuery( '#calendar_booking_unselectable' + resource_id ).length > 0); // FixIn: 8.0.1.2.
596 var is_booking_form_exist = ( jQuery( '#booking_form_div' + resource_id ).length > 0 );
597 if ( ( is_unselectable_calendar ) && ( ! is_booking_form_exist ) ){
598 wpbc_calendar__unselect_all_dates( resource_id ); // Unselect Dates
599 jQuery('.wpbc_only_calendar .popover_calendar_hover').remove(); // Hide all opened popovers
600 return false;
601 }
602
603 jQuery( '#date_booking' + resource_id ).val( date ); // Add selected dates to hidden textarea
604
605
606 if ( 'function' === typeof (wpbc__calendar__do_days_select__bs) ){ wpbc__calendar__do_days_select__bs( date, resource_id ); }
607
608 wpbc_disable_time_fields_in_booking_form( resource_id );
609
610 // Hook -- trigger day selection -----------------------------------------------------------------------------------
611 var mouse_clicked_dates = date; // Can be: "05.10.2023 - 07.10.2023" | "10.10.2023 - 10.10.2023" |
612 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", … ]
613 jQuery( ".booking_form_div" ).trigger( "date_selected", [ resource_id, mouse_clicked_dates, all_selected_dates_arr ] );
614 }
615
616 // Mark middle selected dates with 0.5 opacity // FixIn: 10.3.0.9.
617 jQuery( document ).ready( function (){
618 jQuery( ".booking_form_div" ).on( 'date_selected', function ( event, resource_id, date ){
619 if (
620 ( 'fixed' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ))
621 || ('dynamic' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ))
622 ){
623 var closed_timer = setTimeout( function (){
624 var middle_days_opacity = _wpbc.get_other_param( 'calendars__days_selection__middle_days_opacity' );
625 jQuery( '#calendar_booking' + resource_id + ' .datepick-current-day' ).not( ".selected_check_in_out" ).css( 'opacity', middle_days_opacity );
626 }, 10 );
627 }
628 } );
629 } );
630
631
632 /**
633 * -- T i m e F i e l d s start --------------------------------------------------------------------------
634 */
635
636 /**
637 * Disable time slots in booking form depend on selected dates and booked dates/times
638 *
639 * @param resource_id
640 */
641 function wpbc_disable_time_fields_in_booking_form( resource_id ){
642
643 /**
644 * 1. Get all time fields in the booking form as array of objects
645 * [
646 * { jquery_option: jQuery_Object {}
647 * name: 'rangetime2[]'
648 * times_as_seconds: [ 21600, 23400 ]
649 * value_option_24h: '06:00 - 06:30'
650 * }
651 * ...
652 * { jquery_option: jQuery_Object {}
653 * name: 'starttime2[]'
654 * times_as_seconds: [ 21600 ]
655 * value_option_24h: '06:00'
656 * }
657 * ]
658 */
659 var time_fields_obj_arr = wpbc_get__time_fields__in_booking_form__as_arr( resource_id );
660
661 // 2. Get all selected dates in SQL format like this [ "2023-08-23", "2023-08-24", "2023-08-25", ... ]
662 var selected_dates_arr = wpbc_get__selected_dates_sql__as_arr( resource_id );
663
664 // 3. Get child booking resources or single booking resource that exist in dates
665 var child_resources_arr = wpbc_clone_obj( _wpbc.booking__get_param_value( resource_id, 'resources_id_arr__in_dates' ) );
666
667 var sql_date;
668 var child_resource_id;
669 var merged_seconds;
670 var time_fields_obj;
671 var is_intersect;
672 var is_check_in;
673
674 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 );
675 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 );
676 var allow_past_context = _wpbc.get_other_param( 'this_page_allow_past' );
677 var edit_booking_hash_context = _wpbc.get_other_param( 'this_page_booking_hash' );
678 var is_allow_past_context =
679 ( '1' === String( allow_past_context ) )
680 || ( 1 === allow_past_context )
681 || ( true === allow_past_context )
682 || ( '' !== String( edit_booking_hash_context || '' ) )
683 || ( location.href.indexOf( 'booking_hash' ) > -1 )
684 || ( location.href.indexOf( 'allow_past' ) > -1 );
685
686 // 4. Loop all time Fields options // FixIn: 10.3.0.2.
687 for ( let field_key = 0; field_key < time_fields_obj_arr.length; field_key++ ){
688
689 time_fields_obj_arr[ field_key ].disabled = 0; // By default, this time field is not disabled.
690
691 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 {}}
692
693 // Loop all selected dates.
694 for ( var i = 0; i < selected_dates_arr.length; i++ ) {
695
696 // Get Date: '2023-08-18'.
697 sql_date = selected_dates_arr[i];
698
699 var is_time_in_past = is_allow_past_context ? false : wpbc_check_is_time_in_past( today_time__shift, sql_date, time_fields_obj );
700 // Exception for 'End Time' field, when selected several dates. // FixIn: 10.14.1.5.
701 if ( ( ! is_allow_past_context ) &&
702 ('On' !== _wpbc.calendar__get_param_value( resource_id, 'booking_recurrent_time' )) &&
703 (-1 !== time_fields_obj.name.indexOf( 'endtime' )) &&
704 (selected_dates_arr.length > 1)
705 ) {
706 is_time_in_past = wpbc_check_is_time_in_past( today_time__shift, selected_dates_arr[(selected_dates_arr.length - 1)], time_fields_obj );
707 }
708 if ( is_time_in_past ) {
709 // This time for selected date already in the past.
710 time_fields_obj_arr[field_key].disabled = 1;
711 break; // exist from Dates LOOP.
712 }
713 // FixIn: 9.9.0.31.
714 if (
715 ( 'Off' === _wpbc.calendar__get_param_value( resource_id, 'booking_recurrent_time' ) )
716 && ( selected_dates_arr.length>1 )
717 ){
718 //TODO: skip some fields checking if it's start / end time for mulple dates selection mode.
719 //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
720
721 if ( (0 == i) && (time_fields_obj[ 'name' ].indexOf( 'endtime' ) >= 0) ){
722 break;
723 }
724 if ( ( (selected_dates_arr.length-1) == i ) && (time_fields_obj[ 'name' ].indexOf( 'starttime' ) >= 0) ){
725 break;
726 }
727 }
728
729
730
731 var how_many_resources_intersected = 0;
732 // Loop all resources ID
733 // for ( var res_key in child_resources_arr ){ // FixIn: 10.3.0.2.
734 if ( null === child_resources_arr ) {
735 child_resources_arr = [];
736 }
737 for ( let res_key = 0; res_key < child_resources_arr.length; res_key++ ){
738
739 child_resource_id = child_resources_arr[ res_key ];
740
741 // _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" ]
742 // _wpbc.bookings_in_calendar__get_for_date(2,'2023-08-21')[2].booked_time_slots.merged_seconds = [ [ 25211, 27002 ], [ 36011, 86400 ] ]
743
744 if ( false !== _wpbc.bookings_in_calendar__get_for_date( resource_id, sql_date ) ){
745 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 ] ]
746 } else {
747 merged_seconds = [];
748 }
749 if ( time_fields_obj.times_as_seconds.length > 1 ){
750 is_intersect = wpbc_is_intersect__range_time_interval( [
751 [
752 ( parseInt( time_fields_obj.times_as_seconds[0] ) + 20 ),
753 ( parseInt( time_fields_obj.times_as_seconds[1] ) - 20 )
754 ]
755 ]
756 , merged_seconds );
757 } else {
758 is_check_in = (-1 !== time_fields_obj.name.indexOf( 'start' ));
759 is_intersect = wpbc_is_intersect__one_time_interval(
760 ( ( is_check_in )
761 ? parseInt( time_fields_obj.times_as_seconds ) + 20
762 : parseInt( time_fields_obj.times_as_seconds ) - 20
763 )
764 , merged_seconds );
765 }
766 if (is_intersect){
767 how_many_resources_intersected++; // Increase
768 }
769
770 }
771
772 if ( child_resources_arr.length == how_many_resources_intersected ) {
773 // 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
774
775 time_fields_obj_arr[ field_key ].disabled = 1;
776 break; // exist from Dates LOOP
777 }
778 }
779 }
780
781
782 // 5. Now we can disable time slot in HTML by using ( field.disabled == 1 ) property
783 wpbc__html__time_field_options__set_disabled( time_fields_obj_arr );
784
785 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.
786 }
787
788
789 /**
790 * Check if specific time(-slot) already in the past for selected date
791 *
792 * @param js_current_time_to_check - JS Date
793 * @param sql_date - '2025-01-26'
794 * @param time_fields_obj - Object
795 * @returns {boolean}
796 */
797 function wpbc_check_is_time_in_past( js_current_time_to_check, sql_date, time_fields_obj ) {
798
799 // FixIn: 10.9.6.4
800 var sql_date_arr = sql_date.split( '-' );
801 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 );
802 var sql_date__midnight_miliseconds = sql_date__midnight.getTime();
803
804 var is_intersect = false;
805
806 if ( time_fields_obj.times_as_seconds.length > 1 ) {
807
808 if ( js_current_time_to_check.getTime() > (sql_date__midnight_miliseconds + (parseInt( time_fields_obj.times_as_seconds[0] ) + 20) * 1000) ) {
809 is_intersect = true;
810 }
811 if ( js_current_time_to_check.getTime() > (sql_date__midnight_miliseconds + (parseInt( time_fields_obj.times_as_seconds[1] ) - 20) * 1000) ) {
812 is_intersect = true;
813 }
814
815 } else {
816 var is_check_in = (-1 !== time_fields_obj.name.indexOf( 'start' ));
817
818 var times_as_seconds_check = (is_check_in) ? parseInt( time_fields_obj.times_as_seconds ) + 20 : parseInt( time_fields_obj.times_as_seconds ) - 20;
819
820 times_as_seconds_check = sql_date__midnight_miliseconds + times_as_seconds_check * 1000;
821
822 if ( js_current_time_to_check.getTime() > times_as_seconds_check ) {
823 is_intersect = true;
824 }
825 }
826
827 return is_intersect;
828 }
829
830 /**
831 * Is number inside /intersect of array of intervals ?
832 *
833 * @param time_A - 25800
834 * @param time_interval_B - [ [ 25211, 27002 ], [ 36011, 86400 ] ]
835 * @returns {boolean}
836 */
837 function wpbc_is_intersect__one_time_interval( time_A, time_interval_B ){
838
839 for ( var j = 0; j < time_interval_B.length; j++ ){
840
841 if ( (parseInt( time_A ) > parseInt( time_interval_B[ j ][ 0 ] )) && (parseInt( time_A ) < parseInt( time_interval_B[ j ][ 1 ] )) ){
842 return true
843 }
844
845 // if ( ( parseInt( time_A ) == parseInt( time_interval_B[ j ][ 0 ] ) ) || ( parseInt( time_A ) == parseInt( time_interval_B[ j ][ 1 ] ) ) ) {
846 // // Time A just at the border of interval
847 // }
848 }
849
850 return false;
851 }
852
853 /**
854 * Is these array of intervals intersected ?
855 *
856 * @param time_interval_A - [ [ 21600, 23400 ] ]
857 * @param time_interval_B - [ [ 25211, 27002 ], [ 36011, 86400 ] ]
858 * @returns {boolean}
859 */
860 function wpbc_is_intersect__range_time_interval( time_interval_A, time_interval_B ){
861
862 var is_intersect;
863
864 for ( var i = 0; i < time_interval_A.length; i++ ){
865
866 for ( var j = 0; j < time_interval_B.length; j++ ){
867
868 is_intersect = wpbc_intervals__is_intersected( time_interval_A[ i ], time_interval_B[ j ] );
869
870 if ( is_intersect ){
871 return true;
872 }
873 }
874 }
875
876 return false;
877 }
878
879 /**
880 * Get all time fields in the booking form as array of objects
881 *
882 * @param resource_id
883 * @returns []
884 *
885 * Example:
886 * [
887 * {
888 * value_option_24h: '06:00 - 06:30'
889 * times_as_seconds: [ 21600, 23400 ]
890 * jquery_option: jQuery_Object {}
891 * name: 'rangetime2[]'
892 * }
893 * ...
894 * {
895 * value_option_24h: '06:00'
896 * times_as_seconds: [ 21600 ]
897 * jquery_option: jQuery_Object {}
898 * name: 'starttime2[]'
899 * }
900 * ]
901 */
902 function wpbc_get__time_fields__in_booking_form__as_arr( resource_id ){
903 /**
904 * Fields with [] like this select[name="rangetime1[]"]
905 * it's when we have 'multiple' in shortcode: [select* rangetime multiple "06:00 - 06:30" ... ]
906 */
907 var time_fields_arr=[
908 'select[name="rangetime' + resource_id + '"]',
909 'select[name="rangetime' + resource_id + '[]"]',
910 'select[name="starttime' + resource_id + '"]',
911 'select[name="starttime' + resource_id + '[]"]',
912 'select[name="endtime' + resource_id + '"]',
913 'select[name="endtime' + resource_id + '[]"]'
914 ];
915
916 var time_fields_obj_arr = [];
917
918 // Loop all Time Fields
919 for ( var ctf= 0; ctf < time_fields_arr.length; ctf++ ){
920
921 var time_field = time_fields_arr[ ctf ];
922 var time_option = jQuery( time_field + ' option' );
923
924 // Loop all options in time field
925 for ( var j = 0; j < time_option.length; j++ ){
926
927 var jquery_option = jQuery( time_field + ' option:eq(' + j + ')' );
928 var value_option_seconds_arr = jquery_option.val().split( '-' );
929 var times_as_seconds = [];
930
931 // Get time as seconds
932 if ( value_option_seconds_arr.length ){ // FixIn: 9.8.10.1.
933 for ( let i = 0; i < value_option_seconds_arr.length; i++ ){ // FixIn: 10.0.0.56.
934 // value_option_seconds_arr[i] = '14:00 ' | ' 16:00' (if from 'rangetime') and '16:00' if (start/end time)
935
936 var start_end_times_arr = value_option_seconds_arr[ i ].trim().split( ':' );
937
938 var time_in_seconds = parseInt( start_end_times_arr[ 0 ] ) * 60 * 60 + parseInt( start_end_times_arr[ 1 ] ) * 60;
939
940 times_as_seconds.push( time_in_seconds );
941 }
942 }
943
944 time_fields_obj_arr.push( {
945 'name' : jQuery( time_field ).attr( 'name' ),
946 'value_option_24h': jquery_option.val(),
947 'jquery_option' : jquery_option,
948 'times_as_seconds': times_as_seconds
949 } );
950 }
951 }
952
953 return time_fields_obj_arr;
954 }
955
956 /**
957 * Disable HTML options and add booked CSS class
958 *
959 * @param time_fields_obj_arr - this value is from the func:
960 * wpbc_get__time_fields__in_booking_form__as_arr( resource_id )
961 * [
962 * { jquery_option: jQuery_Object {}
963 * name: 'rangetime2[]'
964 * times_as_seconds: [ 21600, 23400 ]
965 * value_option_24h: '06:00 - 06:30'
966 * disabled = 1
967 * }
968 * ...
969 * { jquery_option: jQuery_Object {}
970 * name: 'starttime2[]'
971 * times_as_seconds: [ 21600 ]
972 * value_option_24h: '06:00'
973 * disabled = 0
974 * }
975 * ]
976 *
977 */
978 function wpbc__html__time_field_options__set_disabled( time_fields_obj_arr ){
979
980 var jquery_option;
981
982 for ( var i = 0; i < time_fields_obj_arr.length; i++ ){
983
984 var jquery_option = time_fields_obj_arr[ i ].jquery_option;
985
986 if ( 1 == time_fields_obj_arr[ i ].disabled ){
987 jquery_option.prop( 'disabled', true ); // Make disable some options
988 jquery_option.addClass( 'booked' ); // Add "booked" CSS class
989
990 // if this booked element selected --> then deselect it
991 if ( jquery_option.prop( 'selected' ) ){
992 jquery_option.prop( 'selected', false );
993
994 jquery_option.parent().find( 'option:not([disabled]):first' ).prop( 'selected', true ).trigger( "change" );
995 }
996
997 } else {
998 jquery_option.prop( 'disabled', false ); // Make active all times
999 jquery_option.removeClass( 'booked' ); // Remove class "booked"
1000 }
1001 }
1002
1003 }
1004
1005 /**
1006 * Check if this time_range | Time_Slot is Full Day booked
1007 *
1008 * @param timeslot_arr_in_seconds - [ 36011, 86400 ]
1009 * @returns {boolean}
1010 */
1011 function wpbc_is_this_timeslot__full_day_booked( timeslot_arr_in_seconds ){
1012
1013 if (
1014 ( timeslot_arr_in_seconds.length > 1 )
1015 && ( parseInt( timeslot_arr_in_seconds[ 0 ] ) < 30 )
1016 && ( parseInt( timeslot_arr_in_seconds[ 1 ] ) > ( (24 * 60 * 60) - 30) )
1017 ){
1018 return true;
1019 }
1020
1021 return false;
1022 }
1023
1024
1025 // -----------------------------------------------------------------------------------------------------------------
1026 /* == S e l e c t e d D a t e s / T i m e - F i e l d s ==
1027 // ----------------------------------------------------------------------------------------------------------------- */
1028
1029 /**
1030 * Get all selected dates in SQL format like this [ "2023-08-23", "2023-08-24" , ... ]
1031 *
1032 * @param resource_id
1033 * @returns {[]} [ "2023-08-23", "2023-08-24", "2023-08-25", "2023-08-26", "2023-08-27", "2023-08-28",
1034 * "2023-08-29" ]
1035 */
1036 function wpbc_get__selected_dates_sql__as_arr( resource_id ){
1037
1038 var selected_dates_arr = [];
1039 selected_dates_arr = jQuery( '#date_booking' + resource_id ).val().split(',');
1040
1041 if ( selected_dates_arr.length ){ // FixIn: 9.8.10.1.
1042 for ( let i = 0; i < selected_dates_arr.length; i++ ){ // FixIn: 10.0.0.56.
1043 selected_dates_arr[ i ] = selected_dates_arr[ i ].trim();
1044 selected_dates_arr[ i ] = selected_dates_arr[ i ].split( '.' );
1045 if ( selected_dates_arr[ i ].length > 1 ){
1046 selected_dates_arr[ i ] = selected_dates_arr[ i ][ 2 ] + '-' + selected_dates_arr[ i ][ 1 ] + '-' + selected_dates_arr[ i ][ 0 ];
1047 }
1048 }
1049 }
1050
1051 // Remove empty elements from an array
1052 selected_dates_arr = selected_dates_arr.filter( function ( n ){ return parseInt(n); } );
1053
1054 selected_dates_arr.sort();
1055
1056 return selected_dates_arr;
1057 }
1058
1059
1060 /**
1061 * Get all time fields in the booking form as array of objects
1062 *
1063 * @param resource_id
1064 * @param is_only_selected_time
1065 * @returns []
1066 *
1067 * Example:
1068 * [
1069 * {
1070 * value_option_24h: '06:00 - 06:30'
1071 * times_as_seconds: [ 21600, 23400 ]
1072 * jquery_option: jQuery_Object {}
1073 * name: 'rangetime2[]'
1074 * }
1075 * ...
1076 * {
1077 * value_option_24h: '06:00'
1078 * times_as_seconds: [ 21600 ]
1079 * jquery_option: jQuery_Object {}
1080 * name: 'starttime2[]'
1081 * }
1082 * ]
1083 */
1084 function wpbc_get__selected_time_fields__in_booking_form__as_arr( resource_id, is_only_selected_time = true ){
1085 /**
1086 * Fields with [] like this select[name="rangetime1[]"]
1087 * it's when we have 'multiple' in shortcode: [select* rangetime multiple "06:00 - 06:30" ... ]
1088 */
1089 var time_fields_arr=[
1090 'select[name="rangetime' + resource_id + '"]',
1091 'select[name="rangetime' + resource_id + '[]"]',
1092 'select[name="starttime' + resource_id + '"]',
1093 'select[name="starttime' + resource_id + '[]"]',
1094 'select[name="endtime' + resource_id + '"]',
1095 'select[name="endtime' + resource_id + '[]"]',
1096 'select[name="durationtime' + resource_id + '"]',
1097 'select[name="durationtime' + resource_id + '[]"]'
1098 ];
1099
1100 var time_fields_obj_arr = [];
1101
1102 // Loop all Time Fields
1103 for ( var ctf= 0; ctf < time_fields_arr.length; ctf++ ){
1104
1105 var time_field = time_fields_arr[ ctf ];
1106
1107 var time_option;
1108 if ( is_only_selected_time ){
1109 time_option = jQuery( '#booking_form' + resource_id + ' ' + time_field + ' option:selected' ); // Exclude conditional fields, because of using '#booking_form3 ...'
1110 } else {
1111 time_option = jQuery( '#booking_form' + resource_id + ' ' + time_field + ' option' ); // All time fields
1112 }
1113
1114
1115 // Loop all options in time field
1116 for ( var j = 0; j < time_option.length; j++ ){
1117
1118 var jquery_option = jQuery( time_option[ j ] ); // Get only selected options //jQuery( time_field + ' option:eq(' + j + ')' );
1119 var value_option_seconds_arr = jquery_option.val().split( '-' );
1120 var times_as_seconds = [];
1121
1122 // Get time as seconds
1123 if ( value_option_seconds_arr.length ){ // FixIn: 9.8.10.1.
1124 for ( let i = 0; i < value_option_seconds_arr.length; i++ ){ // FixIn: 10.0.0.56.
1125 // value_option_seconds_arr[i] = '14:00 ' | ' 16:00' (if from 'rangetime') and '16:00' if (start/end time)
1126
1127 var start_end_times_arr = value_option_seconds_arr[ i ].trim().split( ':' );
1128
1129 var time_in_seconds = parseInt( start_end_times_arr[ 0 ] ) * 60 * 60 + parseInt( start_end_times_arr[ 1 ] ) * 60;
1130
1131 times_as_seconds.push( time_in_seconds );
1132 }
1133 }
1134
1135 time_fields_obj_arr.push( {
1136 'name' : jQuery( '#booking_form' + resource_id + ' ' + time_field ).attr( 'name' ),
1137 'value_option_24h': jquery_option.val(),
1138 'jquery_option' : jquery_option,
1139 'times_as_seconds': times_as_seconds
1140 } );
1141 }
1142 }
1143
1144 // Text: [starttime] - [endtime] -----------------------------------------------------------------------------
1145
1146 var text_time_fields_arr=[
1147 'input[name="starttime' + resource_id + '"]',
1148 'input[name="endtime' + resource_id + '"]',
1149 ];
1150 for ( var tf= 0; tf < text_time_fields_arr.length; tf++ ){
1151
1152 var text_jquery = jQuery( '#booking_form' + resource_id + ' ' + text_time_fields_arr[ tf ] ); // Exclude conditional fields, because of using '#booking_form3 ...'
1153 if ( text_jquery.length > 0 ){
1154
1155 var time__h_m__arr = text_jquery.val().trim().split( ':' ); // '14:00'
1156 if ( 0 == time__h_m__arr.length ){
1157 continue; // Not entered time value in a field
1158 }
1159 if ( 1 == time__h_m__arr.length ){
1160 if ( '' === time__h_m__arr[ 0 ] ){
1161 continue; // Not entered time value in a field
1162 }
1163 time__h_m__arr[ 1 ] = 0;
1164 }
1165 var text_time_in_seconds = parseInt( time__h_m__arr[ 0 ] ) * 60 * 60 + parseInt( time__h_m__arr[ 1 ] ) * 60;
1166
1167 var text_times_as_seconds = [];
1168 text_times_as_seconds.push( text_time_in_seconds );
1169
1170 time_fields_obj_arr.push( {
1171 'name' : text_jquery.attr( 'name' ),
1172 'value_option_24h': text_jquery.val(),
1173 'jquery_option' : text_jquery,
1174 'times_as_seconds': text_times_as_seconds
1175 } );
1176 }
1177 }
1178
1179 return time_fields_obj_arr;
1180 }
1181
1182
1183
1184 // ---------------------------------------------------------------------------------------------------------------------
1185 /* == S U P P O R T for C A L E N D A R ==
1186 // --------------------------------------------------------------------------------------------------------------------- */
1187
1188 /**
1189 * Get Calendar datepick Instance.
1190 *
1191 * @param {int|string} resource_id
1192 * @returns {*|null}
1193 */
1194 function wpbc_calendar__get_inst(resource_id) {
1195
1196 if ( 'undefined' === typeof (resource_id) ) {
1197 resource_id = '1';
1198 }
1199
1200 if ( jQuery( '#calendar_booking' + resource_id ).length > 0 ) {
1201
1202 try {
1203 var inst = jQuery.datepick._getInst( jQuery( '#calendar_booking' + resource_id ).get( 0 ) );
1204 return inst ? inst : null;
1205 } catch ( e ) {
1206 return null;
1207 }
1208 }
1209
1210 return null;
1211 }
1212
1213
1214 /**
1215 * Unselect all dates in calendar and visually update this calendar
1216 *
1217 * @param resource_id ID of booking resource
1218 * @returns {boolean} true on success | false, if no such calendar
1219 */
1220 function wpbc_calendar__unselect_all_dates( resource_id ){
1221
1222 if ( 'undefined' === typeof (resource_id) ){
1223 resource_id = '1';
1224 }
1225
1226 var inst = wpbc_calendar__get_inst( resource_id )
1227
1228 if ( null !== inst ){
1229
1230 // Unselect all dates and set properties of Datepick
1231 jQuery( '#date_booking' + resource_id ).val( '' ); //FixIn: 5.4.3
1232 inst.stayOpen = false;
1233 inst.dates = [];
1234 jQuery.datepick._updateDatepick( inst );
1235
1236 return true
1237 }
1238
1239 return false;
1240
1241 }
1242
1243 /**
1244 * Clear days highlighting in All or specific Calendars
1245 *
1246 * @param resource_id - can be skiped to clear highlighting in all calendars
1247 */
1248 function wpbc_calendars__clear_days_highlighting( resource_id ){
1249
1250 if ( 'undefined' !== typeof ( resource_id ) ){
1251
1252 jQuery( '#calendar_booking' + resource_id + ' .datepick-days-cell-over' ).removeClass( 'datepick-days-cell-over' ); // Clear in specific calendar
1253
1254 } else {
1255 jQuery( '.datepick-days-cell-over' ).removeClass( 'datepick-days-cell-over' ); // Clear in all calendars
1256 }
1257 }
1258
1259 /**
1260 * Scroll to specific month in calendar
1261 *
1262 * @param resource_id ID of resource
1263 * @param year - real year - 2023
1264 * @param month - real month - 12
1265 * @returns {boolean}
1266 */
1267 function wpbc_calendar__scroll_to( resource_id, year, month ){
1268
1269 if ( 'undefined' === typeof (resource_id) ){ resource_id = '1'; }
1270 var inst = wpbc_calendar__get_inst( resource_id )
1271 if ( null !== inst ){
1272
1273 year = parseInt( year );
1274 month = parseInt( month ) - 1; // In JS date, month -1
1275
1276 inst.cursorDate = new Date();
1277 // In some cases, the setFullYear can set only Year, and not the Month and day // FixIn: 6.2.3.5.
1278 inst.cursorDate.setFullYear( year, month, 1 );
1279 inst.cursorDate.setMonth( month );
1280 inst.cursorDate.setDate( 1 );
1281
1282 inst.drawMonth = inst.cursorDate.getMonth();
1283 inst.drawYear = inst.cursorDate.getFullYear();
1284
1285 jQuery.datepick._notifyChange( inst );
1286 jQuery.datepick._adjustInstDate( inst );
1287 jQuery.datepick._showDate( inst );
1288 jQuery.datepick._updateDatepick( inst );
1289
1290 return true;
1291 }
1292 return false;
1293 }
1294
1295 /**
1296 * Is this date selectable in calendar (mainly it's means AVAILABLE date)
1297 *
1298 * @param {int|string} resource_id 1
1299 * @param {string} sql_class_day '2023-08-11'
1300 * @returns {boolean} true | false
1301 */
1302 function wpbc_is_this_day_selectable( resource_id, sql_class_day ){
1303
1304 // Get Data --------------------------------------------------------------------------------------------------------
1305 var date_bookings_obj = _wpbc.bookings_in_calendar__get_for_date( resource_id, sql_class_day );
1306
1307 var is_day_selectable = ( parseInt( date_bookings_obj[ 'day_availability' ] ) > 0 );
1308
1309 if ( typeof (date_bookings_obj[ 'summary' ]) === 'undefined' ){
1310 return is_day_selectable;
1311 }
1312
1313 if ( 'available' != date_bookings_obj[ 'summary']['status_for_day' ] ){
1314
1315 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.
1316 var booking_statuses_arr = wpbc_get_booking_statuses__as_arr( date_bookings_obj );
1317
1318 if (
1319 ( wpbc_booking_statuses__has( booking_statuses_arr, 'pending' ) )
1320 || ( wpbc_booking_statuses__has( booking_statuses_arr, 'pending_pending' ) )
1321 || ( wpbc_booking_statuses__has( booking_statuses_arr, 'pending_approved' ) )
1322 || ( wpbc_booking_statuses__has( booking_statuses_arr, 'approved_pending' ) )
1323 ){
1324 is_day_selectable = (is_day_selectable) ? true : is_set_pending_days_selectable;
1325 }
1326 }
1327
1328 return is_day_selectable;
1329 }
1330
1331 /**
1332 * Is date to check IN array of selected dates
1333 *
1334 * @param {date}js_date_to_check - JS Date - simple JavaScript Date object
1335 * @param {[]} js_dates_arr - [ JSDate, ... ] - array of JS dates
1336 * @returns {boolean}
1337 */
1338 function wpbc_is_this_day_among_selected_days( js_date_to_check, js_dates_arr ){
1339
1340 for ( var date_index = 0; date_index < js_dates_arr.length ; date_index++ ){ // FixIn: 8.4.5.16.
1341 if ( ( js_dates_arr[ date_index ].getFullYear() === js_date_to_check.getFullYear() ) &&
1342 ( js_dates_arr[ date_index ].getMonth() === js_date_to_check.getMonth() ) &&
1343 ( js_dates_arr[ date_index ].getDate() === js_date_to_check.getDate() ) ) {
1344 return true;
1345 }
1346 }
1347
1348 return false;
1349 }
1350
1351 /**
1352 * Get SQL Class Date '2023-08-01' from JS Date
1353 *
1354 * @param date JS Date
1355 * @returns {string} '2023-08-12'
1356 */
1357 function wpbc__get__sql_class_date( date ){
1358
1359 var sql_class_day = date.getFullYear() + '-';
1360 sql_class_day += ( ( date.getMonth() + 1 ) < 10 ) ? '0' : '';
1361 sql_class_day += ( date.getMonth() + 1 ) + '-'
1362 sql_class_day += ( date.getDate() < 10 ) ? '0' : '';
1363 sql_class_day += date.getDate();
1364
1365 return sql_class_day;
1366 }
1367
1368 /**
1369 * Get JS Date from the SQL date format '2024-05-14'
1370 * @param sql_class_date
1371 * @returns {Date}
1372 */
1373 function wpbc__get__js_date( sql_class_date ){
1374
1375 var sql_class_date_arr = sql_class_date.split( '-' );
1376
1377 var date_js = new Date();
1378
1379 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
1380
1381 // Without this time adjust Dates selection in Datepicker can not work!!!
1382 date_js.setHours(0);
1383 date_js.setMinutes(0);
1384 date_js.setSeconds(0);
1385 date_js.setMilliseconds(0);
1386
1387 return date_js;
1388 }
1389
1390 /**
1391 * Get TD Class Date '1-31-2023' from JS Date
1392 *
1393 * @param date JS Date
1394 * @returns {string} '1-31-2023'
1395 */
1396 function wpbc__get__td_class_date( date ){
1397
1398 var td_class_day = (date.getMonth() + 1) + '-' + date.getDate() + '-' + date.getFullYear(); // '1-9-2023'
1399
1400 return td_class_day;
1401 }
1402
1403 /**
1404 * Get date params from string date
1405 *
1406 * @param date string date like '31.5.2023'
1407 * @param separator default '.' can be skipped.
1408 * @returns { {date: number, month: number, year: number} }
1409 */
1410 function wpbc__get__date_params__from_string_date( date , separator){
1411
1412 separator = ( 'undefined' !== typeof (separator) ) ? separator : '.';
1413
1414 var date_arr = date.split( separator );
1415 var date_obj = {
1416 'year' : parseInt( date_arr[ 2 ] ),
1417 'month': (parseInt( date_arr[ 1 ] ) - 1),
1418 'date' : parseInt( date_arr[ 0 ] )
1419 };
1420 return date_obj; // for = new Date( date_obj.year , date_obj.month , date_obj.date );
1421 }
1422
1423 /**
1424 * Add Spin Loader to calendar
1425 * @param resource_id
1426 */
1427 function wpbc_calendar__loading__start( resource_id ){
1428 if ( ! jQuery( '#calendar_booking' + resource_id ).next().hasClass( 'wpbc_spins_loader_wrapper' ) ){
1429 jQuery( '#calendar_booking' + resource_id ).after( '<div class="wpbc_spins_loader_wrapper"><div class="wpbc_spin_loader_one_new"></div></div>' );
1430 }
1431 if ( ! jQuery( '#calendar_booking' + resource_id ).hasClass( 'wpbc_calendar_blur_small' ) ){
1432 jQuery( '#calendar_booking' + resource_id ).addClass( 'wpbc_calendar_blur_small' );
1433 }
1434 wpbc_calendar__blur__start( resource_id );
1435 }
1436
1437 /**
1438 * Remove Spin Loader to calendar
1439 * @param resource_id
1440 */
1441 function wpbc_calendar__loading__stop( resource_id ){
1442 jQuery( '#calendar_booking' + resource_id + ' + .wpbc_spins_loader_wrapper' ).remove();
1443 jQuery( '#calendar_booking' + resource_id ).removeClass( 'wpbc_calendar_blur_small' );
1444 wpbc_calendar__blur__stop( resource_id );
1445 }
1446
1447 /**
1448 * Add Blur to calendar
1449 * @param resource_id
1450 */
1451 function wpbc_calendar__blur__start( resource_id ){
1452 if ( ! jQuery( '#calendar_booking' + resource_id ).hasClass( 'wpbc_calendar_blur' ) ){
1453 jQuery( '#calendar_booking' + resource_id ).addClass( 'wpbc_calendar_blur' );
1454 }
1455 }
1456
1457 /**
1458 * Remove Blur in calendar
1459 * @param resource_id
1460 */
1461 function wpbc_calendar__blur__stop( resource_id ){
1462 jQuery( '#calendar_booking' + resource_id ).removeClass( 'wpbc_calendar_blur' );
1463 }
1464
1465
1466 // .................................................................................................................
1467 /* == Calendar Update - View ==
1468 // ................................................................................................................. */
1469
1470 /**
1471 * Update look of calendar (safe).
1472 *
1473 * In Elementor preview the DOM can be re-rendered, so the calendar element may exist
1474 * while the Datepick instance is missing. In that case try to (re)initialize.
1475 *
1476 * @param {int|string} resource_id
1477 * @return {boolean} true if updated, false if not possible
1478 */
1479 function wpbc_calendar__update_look(resource_id) {
1480
1481 var inst = wpbc_calendar__get_inst( resource_id );
1482
1483 // If instance missing, try to re-init calendar once.
1484 if ( null === inst ) {
1485
1486 var jq_cal = jQuery( '#calendar_booking' + resource_id );
1487
1488 if ( jq_cal.length && ('function' === typeof wpbc_calendar_show) ) {
1489
1490 // Elementor sometimes leaves stale class without real instance.
1491 if ( jq_cal.hasClass( 'hasDatepick' ) ) {
1492 jq_cal.removeClass( 'hasDatepick' );
1493 }
1494
1495 // Try to init datepick markup now.
1496 wpbc_calendar_show( resource_id );
1497
1498 // Try again.
1499 inst = wpbc_calendar__get_inst( resource_id );
1500 }
1501 }
1502
1503 // Still no instance -> do not crash the whole ajax flow.
1504 if ( null === inst ) {
1505 return false;
1506 }
1507
1508 jQuery.datepick._updateDatepick( inst );
1509 return true;
1510 }
1511
1512
1513
1514 /**
1515 * Update dynamically Number of Months in calendar
1516 *
1517 * @param resource_id int
1518 * @param months_number int
1519 */
1520 function wpbc_calendar__update_months_number( resource_id, months_number ){
1521 var inst = wpbc_calendar__get_inst( resource_id );
1522 if ( null !== inst ){
1523 inst.settings[ 'numberOfMonths' ] = months_number;
1524 //_wpbc.calendar__set_param_value( resource_id, 'calendar_number_of_months', months_number );
1525 wpbc_calendar__update_look( resource_id );
1526 }
1527 }
1528
1529
1530 /**
1531 * Show calendar in different Skin
1532 *
1533 * @param selected_skin_url
1534 */
1535 function wpbc__calendar__change_skin( selected_skin_url ){
1536
1537 //console.log( 'SKIN SELECTION ::', selected_skin_url );
1538
1539 // Remove CSS skin
1540 var stylesheet = document.getElementById( 'wpbc-calendar-skin-css' );
1541 stylesheet.parentNode.removeChild( stylesheet );
1542
1543
1544 // Add new CSS skin
1545 var headID = document.getElementsByTagName( "head" )[ 0 ];
1546 var cssNode = document.createElement( 'link' );
1547 cssNode.type = 'text/css';
1548 cssNode.setAttribute( "id", "wpbc-calendar-skin-css" );
1549 cssNode.rel = 'stylesheet';
1550 cssNode.media = 'screen';
1551 cssNode.href = selected_skin_url; //"http://beta/wp-content/plugins/booking/css/skins/green-01.css";
1552 headID.appendChild( cssNode );
1553 }
1554
1555
1556 function wpbc__css__change_skin( selected_skin_url, stylesheet_id = 'wpbc-time_picker-skin-css' ){
1557
1558 // Remove CSS skin
1559 var stylesheet = document.getElementById( stylesheet_id );
1560 stylesheet.parentNode.removeChild( stylesheet );
1561
1562
1563 // Add new CSS skin
1564 var headID = document.getElementsByTagName( "head" )[ 0 ];
1565 var cssNode = document.createElement( 'link' );
1566 cssNode.type = 'text/css';
1567 cssNode.setAttribute( "id", stylesheet_id );
1568 cssNode.rel = 'stylesheet';
1569 cssNode.media = 'screen';
1570 cssNode.href = selected_skin_url; //"http://beta/wp-content/plugins/booking/css/skins/green-01.css";
1571 headID.appendChild( cssNode );
1572 }
1573
1574
1575 // ---------------------------------------------------------------------------------------------------------------------
1576 /* == S U P P O R T M A T H ==
1577 // --------------------------------------------------------------------------------------------------------------------- */
1578
1579 /**
1580 * Merge several intersected intervals or return not intersected:
1581 * [[1,3],[2,6],[8,10],[15,18]] -> [[1,6],[8,10],[15,18]]
1582 *
1583 * @param [] intervals [ [1,3],[2,4],[6,8],[9,10],[3,7] ]
1584 * @returns [] [ [1,8],[9,10] ]
1585 *
1586 * Exmample: wpbc_intervals__merge_inersected( [ [1,3],[2,4],[6,8],[9,10],[3,7] ] );
1587 */
1588 function wpbc_intervals__merge_inersected( intervals ){
1589
1590 if ( ! intervals || intervals.length === 0 ){
1591 return [];
1592 }
1593
1594 var merged = [];
1595 intervals.sort( function ( a, b ){
1596 return a[ 0 ] - b[ 0 ];
1597 } );
1598
1599 var mergedInterval = intervals[ 0 ];
1600
1601 for ( var i = 1; i < intervals.length; i++ ){
1602 var interval = intervals[ i ];
1603
1604 if ( interval[ 0 ] <= mergedInterval[ 1 ] ){
1605 mergedInterval[ 1 ] = Math.max( mergedInterval[ 1 ], interval[ 1 ] );
1606 } else {
1607 merged.push( mergedInterval );
1608 mergedInterval = interval;
1609 }
1610 }
1611
1612 merged.push( mergedInterval );
1613 return merged;
1614 }
1615
1616
1617 /**
1618 * Is 2 intervals intersected: [36011, 86392] <=> [1, 43192] => true ( intersected )
1619 *
1620 * Good explanation here
1621 * https://stackoverflow.com/questions/3269434/whats-the-most-efficient-way-to-test-if-two-ranges-overlap
1622 *
1623 * @param interval_A - [ 36011, 86392 ]
1624 * @param interval_B - [ 1, 43192 ]
1625 *
1626 * @return bool
1627 */
1628 function wpbc_intervals__is_intersected( interval_A, interval_B ) {
1629
1630 if (
1631 ( 0 == interval_A.length )
1632 || ( 0 == interval_B.length )
1633 ){
1634 return false;
1635 }
1636
1637 interval_A[ 0 ] = parseInt( interval_A[ 0 ] );
1638 interval_A[ 1 ] = parseInt( interval_A[ 1 ] );
1639 interval_B[ 0 ] = parseInt( interval_B[ 0 ] );
1640 interval_B[ 1 ] = parseInt( interval_B[ 1 ] );
1641
1642 var is_intersected = Math.max( interval_A[ 0 ], interval_B[ 0 ] ) - Math.min( interval_A[ 1 ], interval_B[ 1 ] );
1643
1644 // if ( 0 == is_intersected ) {
1645 // // Such ranges going one after other, e.g.: [ 12, 15 ] and [ 15, 21 ]
1646 // }
1647
1648 if ( is_intersected < 0 ) {
1649 return true; // INTERSECTED
1650 }
1651
1652 return false; // Not intersected
1653 }
1654
1655
1656 /**
1657 * Get the closets ABS value of element in array to the current myValue
1658 *
1659 * @param myValue - int element to search closet 4
1660 * @param myArray - array of elements where to search [5,8,1,7]
1661 * @returns int 5
1662 */
1663 function wpbc_get_abs_closest_value_in_arr( myValue, myArray ){
1664
1665 if ( myArray.length == 0 ){ // If the array is empty -> return the myValue
1666 return myValue;
1667 }
1668
1669 var obj = myArray[ 0 ];
1670 var diff = Math.abs( myValue - obj ); // Get distance between 1st element
1671 var closetValue = myArray[ 0 ]; // Save 1st element
1672
1673 for ( var i = 1; i < myArray.length; i++ ){
1674 obj = myArray[ i ];
1675
1676 if ( Math.abs( myValue - obj ) < diff ){ // we found closer value -> save it
1677 diff = Math.abs( myValue - obj );
1678 closetValue = obj;
1679 }
1680 }
1681
1682 return closetValue;
1683 }
1684
1685
1686 // ---------------------------------------------------------------------------------------------------------------------
1687 /* == T O O L T I P S ==
1688 // --------------------------------------------------------------------------------------------------------------------- */
1689
1690 /**
1691 * Define tooltip to show, when mouse over Date in Calendar
1692 *
1693 * @param tooltip_text - Text to show 'Booked time: 12:00 - 13:00<br>Cost: $20.00'
1694 * @param resource_id - ID of booking resource '1'
1695 * @param td_class - SQL class '1-9-2023'
1696 * @returns {boolean} - defined to show or not
1697 */
1698 function wpbc_set_tooltip___for__calendar_date( tooltip_text, resource_id, td_class ){
1699
1700 //TODO: make escaping of text for quot symbols, and JS/HTML...
1701
1702 jQuery( '#calendar_booking' + resource_id + ' td.cal4date-' + td_class ).attr( 'data-content', tooltip_text );
1703
1704 var td_el = jQuery( '#calendar_booking' + resource_id + ' td.cal4date-' + td_class ).get( 0 ); // FixIn: 9.0.1.1.
1705
1706 if (
1707 ( 'undefined' !== typeof(td_el) )
1708 && ( undefined == td_el._tippy )
1709 && ( '' !== tooltip_text )
1710 ){
1711
1712 wpbc_tippy( td_el , {
1713 content( reference ){
1714
1715 var popover_content = reference.getAttribute( 'data-content' );
1716
1717 return '<div class="popover popover_tippy">'
1718 + '<div class="popover-content">'
1719 + popover_content
1720 + '</div>'
1721 + '</div>';
1722 },
1723 allowHTML : true,
1724 trigger : 'mouseenter focus',
1725 interactive : false,
1726 hideOnClick : true,
1727 interactiveBorder: 10,
1728 maxWidth : 550,
1729 theme : 'wpbc-tippy-times',
1730 placement : 'top',
1731 delay : [400, 0], // FixIn: 9.4.2.2.
1732 //delay : [0, 9999999999], // Debuge tooltip
1733 ignoreAttributes : true,
1734 touch : true, //['hold', 500], // 500ms delay // FixIn: 9.2.1.5.
1735 appendTo: () => document.body,
1736 });
1737
1738 return true;
1739 }
1740
1741 return false;
1742 }
1743
1744
1745 // ---------------------------------------------------------------------------------------------------------------------
1746 /* == Dates Functions ==
1747 // --------------------------------------------------------------------------------------------------------------------- */
1748
1749 /**
1750 * Get number of dates between 2 JS Dates
1751 *
1752 * @param date1 JS Date
1753 * @param date2 JS Date
1754 * @returns {number}
1755 */
1756 function wpbc_dates__days_between(date1, date2) {
1757
1758 // The number of milliseconds in one day
1759 var ONE_DAY = 1000 * 60 * 60 * 24;
1760
1761 // Convert both dates to milliseconds
1762 var date1_ms = date1.getTime();
1763 var date2_ms = date2.getTime();
1764
1765 // Calculate the difference in milliseconds
1766 var difference_ms = date1_ms - date2_ms;
1767
1768 // Convert back to days and return
1769 return Math.round(difference_ms/ONE_DAY);
1770 }
1771
1772
1773 /**
1774 * Check if this array of dates is consecutive array of dates or not.
1775 * e.g. ['2024-05-09','2024-05-19','2024-05-30'] -> false
1776 * e.g. ['2024-05-09','2024-05-10','2024-05-11'] -> true
1777 * @param sql_dates_arr array e.g.: ['2024-05-09','2024-05-19','2024-05-30']
1778 * @returns {boolean}
1779 */
1780 function wpbc_dates__is_consecutive_dates_arr_range( sql_dates_arr ){ // FixIn: 10.0.0.50.
1781
1782 if ( sql_dates_arr.length > 1 ){
1783 var previos_date = wpbc__get__js_date( sql_dates_arr[ 0 ] );
1784 var current_date;
1785
1786 for ( var i = 1; i < sql_dates_arr.length; i++ ){
1787 current_date = wpbc__get__js_date( sql_dates_arr[i] );
1788
1789 if ( wpbc_dates__days_between( current_date, previos_date ) != 1 ){
1790 return false;
1791 }
1792
1793 previos_date = current_date;
1794 }
1795 }
1796
1797 return true;
1798 }
1799
1800
1801 // ---------------------------------------------------------------------------------------------------------------------
1802 /* == Auto Dates Selection ==
1803 // --------------------------------------------------------------------------------------------------------------------- */
1804
1805 /**
1806 * == How to use ? ==
1807 *
1808 * For Dates selection, we need to use this logic! We need select the dates only after booking data loaded!
1809 *
1810 * Check example bellow.
1811 *
1812 * // Fire on all booking dates loaded
1813 * jQuery( 'body' ).on( 'wpbc_calendar_ajx__loaded_data', function ( event, loaded_resource_id ){
1814 *
1815 * if ( loaded_resource_id == select_dates_in_calendar_id ){
1816 * wpbc_auto_select_dates_in_calendar( select_dates_in_calendar_id, '2024-05-15', '2024-05-25' );
1817 * }
1818 * } );
1819 *
1820 */
1821
1822
1823 /**
1824 * Try to Auto select dates in specific calendar by simulated clicks in datepicker
1825 *
1826 * @param resource_id 1
1827 * @param check_in_ymd '2024-05-09' OR ['2024-05-09','2024-05-19','2024-05-20']
1828 * @param check_out_ymd '2024-05-15' Optional
1829 *
1830 * @returns {number} number of selected dates
1831 *
1832 * Example 1: var num_selected_days = wpbc_auto_select_dates_in_calendar( 1, '2024-05-15',
1833 * '2024-05-25' ); Example 2: var num_selected_days = wpbc_auto_select_dates_in_calendar( 1,
1834 * ['2024-05-09','2024-05-19','2024-05-20'] );
1835 */
1836 function wpbc_auto_select_dates_in_calendar( resource_id, check_in_ymd, check_out_ymd = '' ){ // FixIn: 10.0.0.47.
1837
1838 console.log( 'WPBC_AUTO_SELECT_DATES_IN_CALENDAR( RESOURCE_ID, CHECK_IN_YMD, CHECK_OUT_YMD )', resource_id, check_in_ymd, check_out_ymd );
1839
1840 if (
1841 ( '2100-01-01' == check_in_ymd )
1842 || ( '2100-01-01' == check_out_ymd )
1843 || ( ( '' == check_in_ymd ) && ( '' == check_out_ymd ) )
1844 ){
1845 return 0;
1846 }
1847
1848 // -----------------------------------------------------------------------------------------------------------------
1849 // If check_in_ymd = [ '2024-05-09','2024-05-19','2024-05-30' ] ARRAY of DATES // FixIn: 10.0.0.50.
1850 // -----------------------------------------------------------------------------------------------------------------
1851 var dates_to_select_arr = [];
1852 if ( Array.isArray( check_in_ymd ) ){
1853 dates_to_select_arr = wpbc_clone_obj( check_in_ymd );
1854
1855 // -------------------------------------------------------------------------------------------------------------
1856 // Exceptions to set MULTIPLE DAYS mode
1857 // -------------------------------------------------------------------------------------------------------------
1858 // if dates as NOT CONSECUTIVE: ['2024-05-09','2024-05-19','2024-05-30'], -> set MULTIPLE DAYS mode
1859 if (
1860 ( dates_to_select_arr.length > 0 )
1861 && ( '' == check_out_ymd )
1862 && ( ! wpbc_dates__is_consecutive_dates_arr_range( dates_to_select_arr ) )
1863 ){
1864 wpbc_cal_days_select__multiple( resource_id );
1865 }
1866 // if multiple days to select, but enabled SINGLE day mode, -> set MULTIPLE DAYS mode
1867 if (
1868 ( dates_to_select_arr.length > 1 )
1869 && ( '' == check_out_ymd )
1870 && ( 'single' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ) )
1871 ){
1872 wpbc_cal_days_select__multiple( resource_id );
1873 }
1874 // -------------------------------------------------------------------------------------------------------------
1875 check_in_ymd = dates_to_select_arr[ 0 ];
1876 if ( '' == check_out_ymd ){
1877 check_out_ymd = dates_to_select_arr[ (dates_to_select_arr.length-1) ];
1878 }
1879 }
1880 // -----------------------------------------------------------------------------------------------------------------
1881
1882
1883 if ( '' == check_in_ymd ){
1884 check_in_ymd = check_out_ymd;
1885 }
1886 if ( '' == check_out_ymd ){
1887 check_out_ymd = check_in_ymd;
1888 }
1889
1890 if ( 'undefined' === typeof (resource_id) ){
1891 resource_id = '1';
1892 }
1893
1894
1895 var inst = wpbc_calendar__get_inst( resource_id );
1896
1897 if ( null !== inst ){
1898
1899 // Unselect all dates and set properties of Datepick
1900 jQuery( '#date_booking' + resource_id ).val( '' ); //FixIn: 5.4.3
1901 inst.stayOpen = false;
1902 inst.dates = [];
1903 var check_in_js = wpbc__get__js_date( check_in_ymd );
1904 var td_cell = wpbc_get_clicked_td( inst.id, check_in_js );
1905
1906 // Is ome type of error, then select multiple days selection mode.
1907 if ( '' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ) ) {
1908 _wpbc.calendar__set_param_value( resource_id, 'days_select_mode', 'multiple' );
1909 }
1910
1911
1912 // ---------------------------------------------------------------------------------------------------------
1913 // == DYNAMIC ==
1914 if ( 'dynamic' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ) ){
1915 // 1-st click
1916 inst.stayOpen = false;
1917 jQuery.datepick._selectDay( td_cell, '#' + inst.id, check_in_js.getTime() );
1918 if ( 0 === inst.dates.length ){
1919 return 0; // First click was unsuccessful, so we must not make other click
1920 }
1921
1922 // 2-nd click
1923 var check_out_js = wpbc__get__js_date( check_out_ymd );
1924 var td_cell_out = wpbc_get_clicked_td( inst.id, check_out_js );
1925 inst.stayOpen = true;
1926 jQuery.datepick._selectDay( td_cell_out, '#' + inst.id, check_out_js.getTime() );
1927 }
1928
1929 // ---------------------------------------------------------------------------------------------------------
1930 // == FIXED ==
1931 if ( 'fixed' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' )) {
1932 jQuery.datepick._selectDay( td_cell, '#' + inst.id, check_in_js.getTime() );
1933 }
1934
1935 // ---------------------------------------------------------------------------------------------------------
1936 // == SINGLE ==
1937 if ( 'single' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ) ){
1938 //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!
1939 jQuery.datepick._selectDay( td_cell, '#' + inst.id, check_in_js.getTime() );
1940 }
1941
1942 // ---------------------------------------------------------------------------------------------------------
1943 // == MULTIPLE ==
1944 if ( 'multiple' === _wpbc.calendar__get_param_value( resource_id, 'days_select_mode' ) ){
1945
1946 var dates_arr;
1947
1948 if ( dates_to_select_arr.length > 0 ){
1949 // 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
1950 dates_arr = wpbc_get_selection_dates_js_str_arr__from_arr( dates_to_select_arr );
1951 } else {
1952 dates_arr = wpbc_get_selection_dates_js_str_arr__from_check_in_out( check_in_ymd, check_out_ymd, inst );
1953 }
1954
1955 if ( 0 === dates_arr.dates_js.length ){
1956 return 0;
1957 }
1958
1959 // For Calendar Days selection
1960 for ( var j = 0; j < dates_arr.dates_js.length; j++ ){ // Loop array of dates
1961
1962 var str_date = wpbc__get__sql_class_date( dates_arr.dates_js[ j ] );
1963
1964 // Date unavailable !
1965 if ( 0 == _wpbc.bookings_in_calendar__get_for_date( resource_id, str_date ).day_availability ){
1966 return 0;
1967 }
1968
1969 if ( dates_arr.dates_js[ j ] != -1 ) {
1970 inst.dates.push( dates_arr.dates_js[ j ] );
1971 }
1972 }
1973
1974 var check_out_date = dates_arr.dates_js[ (dates_arr.dates_js.length - 1) ];
1975
1976 inst.dates.push( check_out_date ); // Need add one additional SAME date for correct works of dates selection !!!!!
1977
1978 var checkout_timestamp = check_out_date.getTime();
1979 var td_cell = wpbc_get_clicked_td( inst.id, check_out_date );
1980
1981 jQuery.datepick._selectDay( td_cell, '#' + inst.id, checkout_timestamp );
1982 }
1983
1984
1985 if ( 0 !== inst.dates.length ){
1986 // Scroll to specific month, if we set dates in some future months
1987 wpbc_calendar__scroll_to( resource_id, inst.dates[ 0 ].getFullYear(), inst.dates[ 0 ].getMonth()+1 );
1988 }
1989
1990 return inst.dates.length;
1991 }
1992
1993 return 0;
1994 }
1995
1996 /**
1997 * Get HTML td element (where was click in calendar day cell)
1998 *
1999 * @param calendar_html_id 'calendar_booking1'
2000 * @param date_js JS Date
2001 * @returns {*|jQuery} Dom HTML td element
2002 */
2003 function wpbc_get_clicked_td( calendar_html_id, date_js ){
2004
2005 var td_cell = jQuery( '#' + calendar_html_id + ' .sql_date_' + wpbc__get__sql_class_date( date_js ) ).get( 0 );
2006
2007 return td_cell;
2008 }
2009
2010 /**
2011 * Get arrays of JS and SQL dates as dates array
2012 *
2013 * @param check_in_ymd '2024-05-15'
2014 * @param check_out_ymd '2024-05-25'
2015 * @param inst Datepick Inst. Use wpbc_calendar__get_inst( resource_id );
2016 * @returns {{dates_js: *[], dates_str: *[]}}
2017 */
2018 function wpbc_get_selection_dates_js_str_arr__from_check_in_out( check_in_ymd, check_out_ymd , inst ){
2019
2020 var original_array = [];
2021 var date;
2022 var bk_distinct_dates = [];
2023
2024 var check_in_date = check_in_ymd.split( '-' );
2025 var check_out_date = check_out_ymd.split( '-' );
2026
2027 date = new Date();
2028 date.setFullYear( check_in_date[ 0 ], (check_in_date[ 1 ] - 1), check_in_date[ 2 ] ); // year, month, date
2029 var original_check_in_date = date;
2030 original_array.push( jQuery.datepick._restrictMinMax( inst, jQuery.datepick._determineDate( inst, date, null ) ) ); //add date
2031 if ( ! wpbc_in_array( bk_distinct_dates, (check_in_date[ 2 ] + '.' + check_in_date[ 1 ] + '.' + check_in_date[ 0 ]) ) ){
2032 bk_distinct_dates.push( parseInt(check_in_date[ 2 ]) + '.' + parseInt(check_in_date[ 1 ]) + '.' + check_in_date[ 0 ] );
2033 }
2034
2035 var date_out = new Date();
2036 date_out.setFullYear( check_out_date[ 0 ], (check_out_date[ 1 ] - 1), check_out_date[ 2 ] ); // year, month, date
2037 var original_check_out_date = date_out;
2038
2039 var mewDate = new Date( original_check_in_date.getFullYear(), original_check_in_date.getMonth(), original_check_in_date.getDate() );
2040 mewDate.setDate( original_check_in_date.getDate() + 1 );
2041
2042 while (
2043 (original_check_out_date > date) &&
2044 (original_check_in_date != original_check_out_date) ){
2045 date = new Date( mewDate.getFullYear(), mewDate.getMonth(), mewDate.getDate() );
2046
2047 original_array.push( jQuery.datepick._restrictMinMax( inst, jQuery.datepick._determineDate( inst, date, null ) ) ); //add date
2048 if ( !wpbc_in_array( bk_distinct_dates, (date.getDate() + '.' + parseInt( date.getMonth() + 1 ) + '.' + date.getFullYear()) ) ){
2049 bk_distinct_dates.push( (parseInt(date.getDate()) + '.' + parseInt( date.getMonth() + 1 ) + '.' + date.getFullYear()) );
2050 }
2051
2052 mewDate = new Date( date.getFullYear(), date.getMonth(), date.getDate() );
2053 mewDate.setDate( mewDate.getDate() + 1 );
2054 }
2055 original_array.pop();
2056 bk_distinct_dates.pop();
2057
2058 return {'dates_js': original_array, 'dates_str': bk_distinct_dates};
2059 }
2060
2061 /**
2062 * Get arrays of JS and SQL dates as dates array
2063 *
2064 * @param dates_to_select_arr = ['2024-05-09','2024-05-19','2024-05-30']
2065 *
2066 * @returns {{dates_js: *[], dates_str: *[]}}
2067 */
2068 function wpbc_get_selection_dates_js_str_arr__from_arr( dates_to_select_arr ){ // FixIn: 10.0.0.50.
2069
2070 var original_array = [];
2071 var bk_distinct_dates = [];
2072 var one_date_str;
2073
2074 for ( var d = 0; d < dates_to_select_arr.length; d++ ){
2075
2076 original_array.push( wpbc__get__js_date( dates_to_select_arr[ d ] ) );
2077
2078 one_date_str = dates_to_select_arr[ d ].split('-')
2079 if ( ! wpbc_in_array( bk_distinct_dates, (one_date_str[ 2 ] + '.' + one_date_str[ 1 ] + '.' + one_date_str[ 0 ]) ) ){
2080 bk_distinct_dates.push( parseInt(one_date_str[ 2 ]) + '.' + parseInt(one_date_str[ 1 ]) + '.' + one_date_str[ 0 ] );
2081 }
2082 }
2083
2084 return {'dates_js': original_array, 'dates_str': original_array};
2085 }
2086
2087 // =====================================================================================================================
2088 /* == Auto Fill Fields / Auto Select Dates ==
2089 // ===================================================================================================================== */
2090
2091 jQuery( document ).ready( function (){
2092
2093 var url_params = new URLSearchParams( window.location.search );
2094
2095 // Disable days selection in calendar, after redirection from the "Search results page, after search availability" // FixIn: 8.8.2.3.
2096 if ( 'On' != _wpbc.get_other_param( 'is_enabled_booking_search_results_days_select' ) ) {
2097 if (
2098 ( url_params.has( 'wpbc_select_check_in' ) ) &&
2099 ( url_params.has( 'wpbc_select_check_out' ) ) &&
2100 ( url_params.has( 'wpbc_select_calendar_id' ) )
2101 ){
2102
2103 var select_dates_in_calendar_id = parseInt( url_params.get( 'wpbc_select_calendar_id' ) );
2104
2105 // Fire on all booking dates loaded
2106 jQuery( 'body' ).on( 'wpbc_calendar_ajx__loaded_data', function ( event, loaded_resource_id ){
2107
2108 if ( loaded_resource_id == select_dates_in_calendar_id ){
2109 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' ) );
2110 }
2111 } );
2112 }
2113 }
2114
2115 if ( url_params.has( 'wpbc_auto_fill' ) ){
2116
2117 var wpbc_auto_fill_value = url_params.get( 'wpbc_auto_fill' );
2118
2119 // Convert back. Some systems do not like symbol '~' in URL, so we need to replace to some other symbols
2120 wpbc_auto_fill_value = wpbc_auto_fill_value.replaceAll( '_^_', '~' );
2121
2122 wpbc_auto_fill_booking_fields( wpbc_auto_fill_value );
2123 }
2124
2125 } );
2126
2127 /**
2128 * Autofill / select booking form fields by values from the GET request parameter: ?wpbc_auto_fill=
2129 *
2130 * @param auto_fill_str
2131 */
2132 function wpbc_auto_fill_booking_fields( auto_fill_str ){ // FixIn: 10.0.0.48.
2133
2134 if ( '' == auto_fill_str ){
2135 return;
2136 }
2137
2138 // console.log( 'WPBC_AUTO_FILL_BOOKING_FIELDS( AUTO_FILL_STR )', auto_fill_str);
2139
2140 var fields_arr = wpbc_auto_fill_booking_fields__parse( auto_fill_str );
2141
2142 for ( let i = 0; i < fields_arr.length; i++ ){
2143 jQuery( '[name="' + fields_arr[ i ][ 'name' ] + '"]' ).val( fields_arr[ i ][ 'value' ] );
2144 }
2145 }
2146
2147 /**
2148 * Parse data from get parameter: ?wpbc_auto_fill=visitors231^2~max_capacity231^2
2149 *
2150 * @param data_str = 'visitors231^2~max_capacity231^2';
2151 * @returns {*}
2152 */
2153 function wpbc_auto_fill_booking_fields__parse( data_str ){
2154
2155 var filter_options_arr = [];
2156
2157 var data_arr = data_str.split( '~' );
2158
2159 for ( var j = 0; j < data_arr.length; j++ ){
2160
2161 var my_form_field = data_arr[ j ].split( '^' );
2162
2163 var filter_name = ('undefined' !== typeof (my_form_field[ 0 ])) ? my_form_field[ 0 ] : '';
2164 var filter_value = ('undefined' !== typeof (my_form_field[ 1 ])) ? my_form_field[ 1 ] : '';
2165
2166 filter_options_arr.push(
2167 {
2168 'name' : filter_name,
2169 'value' : filter_value
2170 }
2171 );
2172 }
2173 return filter_options_arr;
2174 }
2175
2176 /**
2177 * Parse data from get parameter: ?search_get__custom_params=...
2178 *
2179 * @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^~';
2180 * @returns {*}
2181 */
2182 function wpbc_auto_fill_search_fields__parse( data_str ){
2183
2184 var filter_options_arr = [];
2185
2186 var data_arr = data_str.split( '~' );
2187
2188 for ( var j = 0; j < data_arr.length; j++ ){
2189
2190 var my_form_field = data_arr[ j ].split( '^' );
2191
2192 var filter_type = ('undefined' !== typeof (my_form_field[ 0 ])) ? my_form_field[ 0 ] : '';
2193 var filter_name = ('undefined' !== typeof (my_form_field[ 1 ])) ? my_form_field[ 1 ] : '';
2194 var filter_value = ('undefined' !== typeof (my_form_field[ 2 ])) ? my_form_field[ 2 ] : '';
2195
2196 filter_options_arr.push(
2197 {
2198 'type' : filter_type,
2199 'name' : filter_name,
2200 'value' : filter_value
2201 }
2202 );
2203 }
2204 return filter_options_arr;
2205 }
2206
2207
2208 // ---------------------------------------------------------------------------------------------------------------------
2209 /* == Auto Update number of months in calendars ON screen size changed ==
2210 // --------------------------------------------------------------------------------------------------------------------- */
2211
2212 /**
2213 * Auto Update Number of Months in Calendar, e.g.: if ( WINDOW_WIDTH <= 782px ) >>> MONTHS_NUMBER = 1
2214 * ELSE: number of months defined in shortcode.
2215 * @param resource_id int
2216 *
2217 */
2218 function wpbc_calendar__auto_update_months_number__on_resize( resource_id ){
2219
2220 if ( true === _wpbc.get_other_param( 'is_allow_several_months_on_mobile' ) ) {
2221 return false;
2222 }
2223
2224 var local__number_of_months = parseInt( _wpbc.calendar__get_param_value( resource_id, 'calendar_number_of_months' ) );
2225
2226 if ( local__number_of_months > 1 ){
2227
2228 if ( jQuery( window ).width() <= 782 ){
2229 wpbc_calendar__update_months_number( resource_id, 1 );
2230 } else {
2231 wpbc_calendar__update_months_number( resource_id, local__number_of_months );
2232 }
2233
2234 }
2235 }
2236
2237 /**
2238 * Auto Update Number of Months in ALL Calendars
2239 *
2240 */
2241 function wpbc_calendars__auto_update_months_number(){
2242
2243 var all_calendars_arr = _wpbc.calendars_all__get();
2244
2245 // This LOOP "for in" is GOOD, because we check here keys 'calendar_' === calendar_id.slice( 0, 9 )
2246 for ( var calendar_id in all_calendars_arr ){
2247 if ( 'calendar_' === calendar_id.slice( 0, 9 ) ){
2248 var resource_id = parseInt( calendar_id.slice( 9 ) ); // 'calendar_3' -> 3
2249 if ( resource_id > 0 ){
2250 wpbc_calendar__auto_update_months_number__on_resize( resource_id );
2251 }
2252 }
2253 }
2254 }
2255
2256 /**
2257 * If browser window changed, then update number of months.
2258 */
2259 jQuery( window ).on( 'resize', function (){
2260 wpbc_calendars__auto_update_months_number();
2261 } );
2262
2263 /**
2264 * Auto update calendar number of months on initial page load
2265 */
2266 jQuery( document ).ready( function (){
2267 var closed_timer = setTimeout( function (){
2268 wpbc_calendars__auto_update_months_number();
2269 }, 100 );
2270 });
2271
2272 // ---------------------------------------------------------------------------------------------------------------------
2273 /* == Check: calendar_dates_start: "2026-01-01", calendar_dates_end: "2026-12-31" == // FixIn: 10.13.1.4.
2274 // --------------------------------------------------------------------------------------------------------------------- */
2275 /**
2276 * Get Start JS Date of starting dates in calendar, from the _wpbc object.
2277 *
2278 * @param integer resource_id - resource ID, e.g.: 1.
2279 */
2280 function wpbc_calendar__get_dates_start( resource_id ) {
2281 return wpbc_calendar__get_date_parameter( resource_id, 'calendar_dates_start' );
2282 }
2283
2284 /**
2285 * Get End JS Date of ending dates in calendar, from the _wpbc object.
2286 *
2287 * @param integer resource_id - resource ID, e.g.: 1.
2288 */
2289 function wpbc_calendar__get_dates_end(resource_id) {
2290 return wpbc_calendar__get_date_parameter( resource_id, 'calendar_dates_end' );
2291 }
2292
2293 /**
2294 * Get validates date parameter.
2295 *
2296 * @param resource_id - 1
2297 * @param parameter_str - 'calendar_dates_start' | 'calendar_dates_end' | ...
2298 */
2299 function wpbc_calendar__get_date_parameter(resource_id, parameter_str) {
2300
2301 var date_expected_ymd = _wpbc.calendar__get_param_value( resource_id, parameter_str );
2302
2303 if ( ! date_expected_ymd ) {
2304 return false; // '' | 0 | null | undefined -> false.
2305 }
2306
2307 if ( -1 !== date_expected_ymd.indexOf( '-' ) ) {
2308
2309 var date_expected_ymd_arr = date_expected_ymd.split( '-' ); // '2025-07-26' -> ['2025', '07', '26']
2310
2311 if ( date_expected_ymd_arr.length > 0 ) {
2312 var year = (date_expected_ymd_arr.length > 0) ? parseInt( date_expected_ymd_arr[0] ) : new Date().getFullYear(); // Year.
2313 var month = (date_expected_ymd_arr.length > 1) ? (parseInt( date_expected_ymd_arr[1] ) - 1) : 0; // (month - 1) or 0 - Jan.
2314 var day = (date_expected_ymd_arr.length > 2) ? parseInt( date_expected_ymd_arr[2] ) : 1; // date or Otherwise 1st of month
2315
2316 var date_js = new Date( year, month, day, 0, 0, 0, 0 );
2317
2318 return date_js;
2319 }
2320 }
2321
2322 return false; // Fallback, if we not parsed this parameter 'calendar_dates_start' = '2025-07-26', for example because of 'calendar_dates_start' = 'sfsdf'.
2323 }
2324