PluginProbe
Booking Calendar / 11.8.4
Booking Calendar v11.8.4
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
← All changes | js/wpbc_times.js +238 -90 10.1011.8.4 View file →
@@ -1,7 +1,79 @@
1 1 var start_time_checking_index;
2 2
3 3 /**
4 + * Check if the date has only Working Time limits, without real bookings or manually blocked time slots.
5 + *
6 + * Working Time intervals still have to stay in the booking data for validation and tooltips,
7 + * but they should not produce the small dots inside calendar day cells.
8 + *
9 + * @param {Object} date_bookings_obj
10 + * @param {Array} child_resources_arr
11 + * @returns {boolean}
12 + */
13 +function wpbc_is_date_has_only_working_time_limits_for_dots( date_bookings_obj, child_resources_arr ) {
14 +
15 + var has_working_time_limits = false;
16 + var has_real_time_limits = false;
17 + var resource_day_obj;
18 + var time_details_obj;
19 + var time_details;
20 + var source_type;
21 +
22 + if ( ( ! date_bookings_obj ) || ( null === child_resources_arr ) ) {
23 + return false;
24 + }
25 +
26 + if (
27 + ( date_bookings_obj[ 'summary' ] )
28 + && ( date_bookings_obj[ 'summary' ][ 'status_for_bookings' ] )
29 + && ( '' !== date_bookings_obj[ 'summary' ][ 'status_for_bookings' ] )
30 + ) {
31 + return false;
32 + }
33 +
34 + for ( var i = 0; i < child_resources_arr.length; i++ ) {
35 +
36 + resource_day_obj = date_bookings_obj[ child_resources_arr[ i ] ];
37 +
38 + if ( ! resource_day_obj ) {
39 + continue;
40 + }
41 +
42 + time_details_obj = resource_day_obj[ '__booked__times__details' ];
43 +
44 + if ( ! time_details_obj ) {
45 + if (
46 + ( resource_day_obj.booked_time_slots )
47 + && ( resource_day_obj.booked_time_slots.merged_seconds )
48 + && ( resource_day_obj.booked_time_slots.merged_seconds.length > 0 )
49 + ) {
50 + has_real_time_limits = true;
51 + }
52 + continue;
53 + }
54 +
55 + for ( var time_key in time_details_obj ) {
56 +
57 + if ( ! time_details_obj.hasOwnProperty( time_key ) ) {
58 + continue;
59 + }
60 +
61 + time_details = time_details_obj[ time_key ];
62 + source_type = ( time_details && ( 'undefined' !== typeof( time_details[ 'source_type' ] ) ) ) ? time_details[ 'source_type' ] : 'booking';
63 +
64 + if ( 'working_time' === source_type ) {
65 + has_working_time_limits = true;
66 + } else {
67 + has_real_time_limits = true;
68 + }
69 + }
70 + }
71 +
72 + return ( has_working_time_limits && ! has_real_time_limits );
73 +}
74 +
75 +/**
4 76 * Get dots for partially booked dates.
5 77 * For parent booking resources with specific capacity,
6 78 * System do not show partially booked dates, if at least one child booking resource fully available
7 79 * Otherwise it show maximum number of time-slot in one specific child booking resource
@@ -24,9 +96,14 @@
24 96 var child_resources_arr = wpbc_clone_obj(_wpbc.booking__get_param_value(resource_id, 'resources_id_arr__in_dates'));
25 97
26 98 // '2023-08-21'
27 99 var sql_date = wpbc__get__sql_class_date(new Date(my_thisDateTime));
100 + var date_bookings_obj = _wpbc.bookings_in_calendar__get_for_date(resource_id, sql_date);
28 101
102 + if ( wpbc_is_date_has_only_working_time_limits_for_dots( date_bookings_obj, child_resources_arr ) ) {
103 + return '';
104 + }
105 +
29 106 var child_resource_id;
30 107 var merged_seconds;
31 108 var dots_count = 0;
32 109
@@ -38,10 +115,10 @@
38 115
39 116 // _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" ]
40 117 // _wpbc.bookings_in_calendar__get_for_date(2,'2023-08-21')[2].booked_time_slots.merged_seconds = [ [ 25211, 27002 ], [ 36011, 86400 ] ]
41 118
42 - if (false !== _wpbc.bookings_in_calendar__get_for_date(resource_id, sql_date)) {
43 - 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 ] ]
119 + if (false !== date_bookings_obj) {
120 + merged_seconds = date_bookings_obj[child_resource_id].booked_time_slots.merged_seconds; // [ [ 25211, 27002 ], [ 36011, 86400 ] ]
44 121 } else {
45 122 merged_seconds = [];
46 123 }
47 124
@@ -219,19 +296,154 @@
219 296
220 297 return false;
221 298 }
222 299
300 +function wpbc_is_change_over_enabled_for_resource( resource_id ) {
223 301
224 -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
302 + if ( ( 'undefined' !== typeof resource_id ) && ( null !== resource_id ) ) {
303 + var resource_change_over = _wpbc.calendar__get_param_value( resource_id, 'is_enabled_change_over' );
304 + if ( '' !== resource_change_over ) {
305 + return ( true === resource_change_over ) || ( 'true' === resource_change_over );
306 + }
307 + }
308 +
309 + return true === _wpbc.get_other_param( 'is_enabled_change_over' );
310 +}
311 +
312 +
313 +/**
314 + * Check if the selected date/time is already in the past compared to "today_arr".
315 + *
316 + * Behavior notes:
317 + * - If "is_enabled_change_over" is enabled, always returns false (no restriction).
318 + * - `sort_date_array[0]` is expected to be the earliest selected date (sorted ascending).
319 + * - `today_arr` is expected to be: [YYYY, MM, DD, HH, mm] (strings or numbers).
320 + * - `myTime` is expected to be "HH:MM" (24h).
321 + *
322 + * @param {string} myTime Time string in "HH:MM" format.
323 + * @param {Array<Array<string|number>>} sort_date_array Array of date arrays; first element is used as date to check.
324 + * @returns {boolean} True if selected date/time is in the past, otherwise false.
325 + */
326 +function wpbc_is_time_in_the_past_for_today(myTime, sort_date_array, resource_id) {
327 +
328 + var allow_past_context = _wpbc.get_other_param( 'this_page_allow_past' );
329 + var edit_booking_hash_context = _wpbc.get_other_param( 'this_page_booking_hash' );
330 + if (
331 + ( '1' === String( allow_past_context ) )
332 + || ( 1 === allow_past_context )
333 + || ( true === allow_past_context )
334 + || ( '' !== String( edit_booking_hash_context || '' ) )
335 + || ( location.href.indexOf( 'booking_hash' ) > -1 )
336 + || ( location.href.indexOf( 'allow_past' ) > -1 )
337 + ) {
338 + return false;
339 + }
340 +
341 + // FixIn: 10.14.10.2.
342 + if ( true === wpbc_is_change_over_enabled_for_resource( resource_id ) ) {
343 + return false;
344 + }
345 + var date_to_check = sort_date_array[0];
346 + if ( parseInt( date_to_check[0] ) < parseInt( _wpbc.get_other_param( 'today_arr' )[0] ) ) {
347 + return true;
348 + }
349 + if (
350 + (parseInt( date_to_check[0] ) == parseInt( _wpbc.get_other_param( 'today_arr' )[0] )) &&
351 + (parseInt( date_to_check[1] ) < parseInt( _wpbc.get_other_param( 'today_arr' )[1] ))
352 + ) {
353 + return true;
354 + }
355 + if (
356 + (parseInt( date_to_check[0] ) == parseInt( _wpbc.get_other_param( 'today_arr' )[0] )) &&
357 + (parseInt( date_to_check[1] ) == parseInt( _wpbc.get_other_param( 'today_arr' )[1] )) &&
358 + (parseInt( date_to_check[2] ) < parseInt( _wpbc.get_other_param( 'today_arr' )[2] ))
359 + ) {
360 + return true;
361 + }
362 + if (
363 + (parseInt( date_to_check[0] ) == parseInt( _wpbc.get_other_param( 'today_arr' )[0] )) &&
364 + (parseInt( date_to_check[1] ) == parseInt( _wpbc.get_other_param( 'today_arr' )[1] )) &&
365 + (parseInt( date_to_check[2] ) == parseInt( _wpbc.get_other_param( 'today_arr' )[2] ))
366 + ) {
367 + var mytime_value = myTime.split( ":" );
368 + mytime_value = parseInt( mytime_value[0] ) * 60 + parseInt( mytime_value[1] );
369 +
370 + var current_time_value = parseInt( _wpbc.get_other_param( 'today_arr' )[3] ) * 60 + parseInt( _wpbc.get_other_param( 'today_arr' )[4] );
371 +
372 + if ( current_time_value > mytime_value ) {
373 + return true;
374 + }
375 + }
376 + return false;
377 +}
378 +
379 +/**
380 + * Validate a time string.
381 + *
382 + * Supported formats:
383 + * - 24-hour time: "H:MM" or "HH:MM"
384 + * Examples: "0:00", "09:30", "23:59", "24:00"
385 + * Notes: "24:00" is allowed, but "24:01" is not.
386 + *
387 + * - 12-hour time: "H:MM AM/PM" (AM/PM is case-insensitive; spaces are optional)
388 + * Examples: "9:30 AM", "09:30pm", "12:05 PM"
389 + *
390 + * @param {string} time_str Raw time string entered by the user.
391 + * @returns {boolean} True if the string matches a valid supported time format.
392 + */
393 +function wpbc_is_valid_time_string(time_str) {
394 +
395 + if ( typeof time_str !== 'string' ) {
396 + return false;
397 + }
398 +
399 + const str = time_str.trim();
400 + if ( str === '' ) {
401 + return false;
402 + }
403 +
404 + // 1-2 digit hours, 2 digit minutes, optional AM/PM (case-insensitive).
405 + const match = str.match( /^(\d{1,2}):(\d{2})(?:\s*([AaPp][Mm]))?$/ );
406 + if ( ! match ) {
407 + return false;
408 + }
409 +
410 + const hour = Number( match[1] );
411 + const minute = Number( match[2] );
412 + const ampm = match[3] ? match[3].toUpperCase() : null;
413 +
414 + if ( ! Number.isInteger( hour ) || ! Number.isInteger( minute ) ) {
415 + return false;
416 + }
417 +
418 + if ( minute < 0 || minute > 59 ) {
419 + return false;
420 + }
421 +
422 + // 12-hour mode (AM/PM provided): hour must be 1..12.
423 + if ( ampm ) {
424 + return hour >= 1 && hour <= 12;
425 + }
426 +
427 + // 24-hour mode (no AM/PM): hour must be 0..24, but 24 only allowed with :00.
428 + if ( hour < 0 || hour > 24 ) {
429 + return false;
430 + }
431 + if ( hour === 24 && minute !== 0 ) {
432 + return false;
433 + }
434 +
435 + return true;
436 +}
437 +
438 +
225 439 //TODO: Continue Refactoring here 2018-04-21
226 -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
227 440
228 -
229 - //PS: This function from ../booking/inc/js/personal.js
441 + //PS: This function from personal.js
230 442 function wpbc_is_this_time_selection_not_available( resource_id, form_elements ){
231 443
232 444 // Skip this checking if we are in the Admin panel at Add booking page
233 - if ( location.href.indexOf( 'page=wpbc-new' ) > 0 ) {
445 + if ( ( location.href.indexOf( 'page=wpbc' ) > 0 ) && ( location.href.indexOf( 'tab=add-booking' ) > 0 ) ) {
234 446 return false;
235 447 }
236 448
237 449 var count = form_elements.length;
@@ -255,8 +467,12 @@
255 467 if ( jQuery( element ).closest( '.booking_form_garbage' ).length ){ // FixIn: 7.1.2.14.
256 468 continue;
257 469 }
258 470
471 + if ( '1' === String( jQuery( element ).attr( 'data-wpbc-booking-submit-ignore' ) || '' ) ) {
472 + continue;
473 + }
474 +
259 475 if (
260 476 ( element.name != undefined )
261 477 && ( element.name.indexOf( 'hint' ) === -1 ) //FixIn: 9.5.5.2 // FixIn: 9.6.3.9.
262 478 ){
@@ -262,9 +478,9 @@
262 478 ){
263 479 var my_element = element.name; //.toString();
264 480 if ( my_element.indexOf( 'rangetime' ) !== -1 ){ // Range Time
265 481 if ( element.value == '' ){ //FixIn: 7.0.Beta.19
266 - var notice_message_id = wpbc_front_end__show_message__warning( element, _wpbc.get_message( 'message_check_required' ) );
482 + var notice_message_id = wpbc_front_end__show_message__warning( element, _wpbc.get_message( 'message_check_required' ), 'text' );
267 483 return true;
268 484 }
269 485 var my_rangetime = element.value.split( '-' );
270 486 if ( my_rangetime.length > 1 ){
@@ -318,10 +534,10 @@
318 534
319 535 var valid_time = true;
320 536 if ( (start_time == '') || (end_time == '') ) valid_time = false;
321 537
322 - if ( !isValidTimeTextField( start_time ) ) valid_time = false;
323 - if ( !isValidTimeTextField( end_time ) ) valid_time = false;
538 + if ( !wpbc_is_valid_time_string( start_time ) ) valid_time = false;
539 + if ( !wpbc_is_valid_time_string( end_time ) ) valid_time = false;
324 540
325 541 if ( valid_time === true )
326 542 if (
327 543 (typeof(checkRecurentTimeInside) == 'function') &&
@@ -343,15 +559,15 @@
343 559 }
344 560
345 561 if ( valid_time !== true ){
346 562 //return false; // do not show warning for setting pending days selectable, if making booking for time-slot // FixIn: 7.0.1.23.
347 - if ( (_wpbc.get_other_param( 'is_enabled_change_over' )) && (element_start !== false) && (element_end !== false) ){ // FixIn: 6.1.1.1.
348 - wpbc_front_end__show_message__warning_under_element( '#date_booking' + resource_id, _wpbc.get_message( 'message_check_no_selected_dates' ) );
563 + if ( ( wpbc_is_change_over_enabled_for_resource( resource_id ) ) && (element_start !== false) && (element_end !== false) ){ // FixIn: 6.1.1.1.
564 + wpbc_front_end__show_message__warning( '#booking_form_div' + resource_id + ' .bk_calendar_frame', _wpbc.get_message( 'message_check_no_selected_dates' ), 'text' );
349 565 }
350 - if ( element_rangetime !== false ){ wpbc_front_end__show_message__warning_under_element( element_rangetime, _wpbc.get_message( 'message_error_range_time' ) ); }
351 - if ( element_duration !== false ){ wpbc_front_end__show_message__warning_under_element( element_duration, _wpbc.get_message( 'message_error_duration_time' ) ); }
352 - if ( element_start !== false ){ wpbc_front_end__show_message__warning_under_element( element_start, _wpbc.get_message( 'message_error_start_time' ) ); }
353 - if ( element_end !== false ){ wpbc_front_end__show_message__warning_under_element( element_end, _wpbc.get_message( 'message_error_end_time' ) ); }
566 + if ( element_rangetime !== false ){ wpbc_front_end__show_message__warning_under_element( element_rangetime, _wpbc.get_message( 'message_error_range_time' ), 'text' ); }
567 + if ( element_duration !== false ){ wpbc_front_end__show_message__warning_under_element( element_duration, _wpbc.get_message( 'message_error_duration_time' ), 'text' ); }
568 + if ( element_start !== false ){ wpbc_front_end__show_message__warning_under_element( element_start, _wpbc.get_message( 'message_error_start_time' ), 'text' ); }
569 + if ( element_end !== false ){ wpbc_front_end__show_message__warning_under_element( element_end, _wpbc.get_message( 'message_error_end_time' ), 'text' ); }
354 570
355 571 return true;
356 572
357 573 } else {
@@ -362,45 +578,8 @@
362 578
363 579
364 580 }
365 581
366 -
367 -function isTimeTodayGone( myTime, sort_date_array ){
368 - var date_to_check = sort_date_array[ 0 ];
369 - if ( parseInt( date_to_check[0] ) < parseInt( _wpbc.get_other_param( 'today_arr' )[0] ) ) {
370 - return true;
371 - }
372 - if (
373 - (parseInt( date_to_check[0] ) == parseInt( _wpbc.get_other_param( 'today_arr' )[0] )) &&
374 - (parseInt( date_to_check[1] ) < parseInt( _wpbc.get_other_param( 'today_arr' )[1] ))
375 - ){
376 - return true;
377 - }
378 - if (
379 - (parseInt( date_to_check[0] ) == parseInt( _wpbc.get_other_param( 'today_arr' )[0] )) &&
380 - (parseInt( date_to_check[1] ) == parseInt( _wpbc.get_other_param( 'today_arr' )[1] )) &&
381 - (parseInt( date_to_check[2] ) < parseInt( _wpbc.get_other_param( 'today_arr' )[2] ))
382 - ) {
383 - return true;
384 - }
385 - if (
386 - (parseInt( date_to_check[0] ) == parseInt( _wpbc.get_other_param( 'today_arr' )[0] )) &&
387 - (parseInt( date_to_check[1] ) == parseInt( _wpbc.get_other_param( 'today_arr' )[1] )) &&
388 - (parseInt( date_to_check[2] ) == parseInt( _wpbc.get_other_param( 'today_arr' )[2] ))
389 - ) {
390 - var mytime_value = myTime.split( ":" );
391 - mytime_value = parseInt( mytime_value[0] ) * 60 + parseInt( mytime_value[1] );
392 -
393 - var current_time_value = parseInt( _wpbc.get_other_param( 'today_arr' )[3] ) * 60 + parseInt( _wpbc.get_other_param( 'today_arr' )[4] );
394 -
395 - if ( current_time_value > mytime_value ) {
396 - return true;
397 - }
398 - }
399 - return false;
400 -}
401 -
402 -
403 582 function checkTimeInside( mytime, is_start_time, bk_type ){
404 583
405 584 var my_dates_str = document.getElementById( 'date_booking' + bk_type ).value; // GET DATES From TEXTAREA
406 585
@@ -411,9 +590,8 @@
411 590
412 591 return checkTimeInsideProcess( mytime, is_start_time, bk_type, my_dates_str );
413 592 }
414 593
415 -
416 594 function checkRecurentTimeInside( my_rangetime, bk_type ){
417 595
418 596 var valid_time = true;
419 597 var my_dates_str = document.getElementById( 'date_booking' + bk_type ).value; // GET DATES From TEXTAREA
@@ -435,14 +613,16 @@
435 613
436 614 return valid_time;
437 615 }
438 616
439 -
440 -// Function check start and end time at selected days
617 + // Function check start and end time at selected days.
441 618 function checkTimeInsideProcess( mytime, is_start_time, bk_type, my_dates_str ){
442 619 var i, h, s, m; // FixIn: 9.1.5.1.
443 620
444 - var date_array = my_dates_str.split( ", " );
621 + var date_array = my_dates_str.split( ',' );
622 + date_array = date_array.map( function (s) {
623 + return s.trim();
624 + } );
445 625 if ( date_array.length == 2 ){ // This recheck is need for editing booking, with single day
446 626 if ( date_array[ 0 ] == date_array[ 1 ] ){
447 627 date_array = [ date_array[ 0 ] ];
448 628 }
@@ -464,9 +644,9 @@
464 644 sort_date_array[ i ] = [ parseInt( sort_date_array[ i ][ 0 ] * 1 ), parseInt( sort_date_array[ i ][ 1 ] * 1 ), parseInt( sort_date_array[ i ][ 2 ] * 1 ) ]; // [2009,7,1],...
465 645 }
466 646
467 647 if ( is_start_time ) {
468 - if ( isTimeTodayGone( mytime, sort_date_array ) ) {
648 + if ( wpbc_is_time_in_the_past_for_today( mytime, sort_date_array, bk_type ) ) {
469 649 return false;
470 650 }
471 651 }
472 652
@@ -591,39 +771,7 @@
591 771 else {
592 772 if ( start_time_checking_index != undefined )
593 773 if ( start_time_checking_index[ 2 ] != undefined )
594 774 if ( (sort_date_array.length == 1) && (start_time_checking_index[ 2 ] >= mytime_value) ) return false; // we are select only one day and end time is earlythe starttime its wrong
595 - }
596 - return true;
597 - }
598 -
599 -
600 - //PS: This function from ../booking/inc/js/personal.js
601 - function isValidTimeTextField( timeStr ){
602 - // Checks if time is in HH:MM AM/PM format.
603 - // The seconds and AM/PM are optional.
604 -
605 - var timePat = /^(\d{1,2}):(\d{2})(\s?(AM|am|PM|pm))?$/;
606 -
607 - var matchArray = timeStr.match( timePat );
608 - if ( matchArray == null ){
609 - return false; //("<?php esc_html_e('Time is not in a valid format. Use this format HH:MM or HH:MM AM/PM'); ?>");
610 - }
611 - var hour = matchArray[ 1 ];
612 - var minute = matchArray[ 2 ];
613 - var ampm = matchArray[ 4 ];
614 -
615 - if ( ampm == "" ){
616 - ampm = null
617 - }
618 -
619 - if ( hour < 0 || hour > 24 ){ // FixIn: 8.3.1.1.
620 - return false; //("<?php esc_html_e('Hour must be between 1 and 12. (or 0 and 23 for military time)'); ?>");
621 - }
622 - if ( hour > 12 && ampm != null ){
623 - return false; //("<?php esc_html_e('You can not specify AM or PM for military time.'); ?>");
624 - }
625 - if ( minute < 0 || minute > 59 ){
626 - return false; //("<?php esc_html_e('Minute must be between 0 and 59.'); ?>");
627 775 }
628 776 return true;
629 777 }