1/** 2 * Check errors in booking form fields, and show warnings if some errors exist. 3 * Check errors, like not selected dates or not filled requred form fields, or not correct entering email or phone 4 * fields, etc... 5 * 6 * @param resource_id int (ID of booking resource) 7 */ 8function wpbc_check_errors_in_booking_form( resource_id ) { 9 var $form = jQuery( '#booking_form' + resource_id ); 10 var fields_with_errors_arr = []; 11 var is_error_in_field = false; 12 var skip_element_types = [ 'hidden', 'button' ]; 13 14 if ( ! $form.length ) { 15 return false; 16 } 17 18 /** 19 * Show a validation warning and register the related field as invalid. 20 * 21 * @param {HTMLElement|null} field Field to focus after validation. 22 * @param {HTMLElement|jQuery|string} target Warning message target. 23 * @param {string} message Warning message. 24 */ 25 function add_validation_error( field, target, message ) { 26 wpbc_front_end__show_message__warning( target, message, 'text' ); 27 is_error_in_field = true; 28 29 if ( field ) { 30 fields_with_errors_arr.push( field ); 31 } 32 } 33 34 /** 35 * Validate a required field. 36 * 37 * @param {HTMLElement} field Form field. 38 * @param {jQuery} $field Cached jQuery field. 39 * @param {string} field_type Field type. 40 */ 41 function validate_required_field( field, $field, field_type ) { 42 var warning_target; 43 44 if ( ! $field.hasClass( 'wpdev-validates-as-required' ) ) { 45 return; 46 } 47 48 if ( 'checkbox' === field_type ) { 49 if ( ! $field.is( ':checked' ) && ! jQuery( ':checkbox[name="' + field.name + '"]', $form ).is( ':checked' ) ) { 50 warning_target = $field.parents( '.wpdev-form-control-wrap' ).last(); 51 52 if ( ! warning_target.length ) { 53 warning_target = $field.parents( '.controls' ).last(); 54 } 55 if ( ! warning_target.length ) { 56 warning_target = $field; 57 } 58 59 add_validation_error( field, warning_target, _wpbc.get_message( 'message_check_required_for_check_box' ) ); 60 } 61 return; 62 } 63 64 if ( 'radio' === field_type ) { 65 if ( ! jQuery( ':radio[name="' + field.name + '"]', $form ).is( ':checked' ) ) { 66 add_validation_error( field, $field.parents( '.wpdev-form-control-wrap' ), _wpbc.get_message( 'message_check_required_for_radio_box' ) ); 67 } 68 return; 69 } 70 71 if ( '' === wpbc_trim( $field.val() ) ) { 72 add_validation_error( field, field, _wpbc.get_message( 'message_check_required' ) ); 73 } 74 } 75 76 /** 77 * Validate an email field and return its trimmed value. 78 * 79 * @param {HTMLElement} field Form field. 80 * @param {jQuery} $field Cached jQuery field. 81 * @returns {string} 82 */ 83 function validate_email_field( field, $field ) { 84 var email_value = String( $field.val() || '' ).replace( /^\s+|\s+$/gm, '' ); 85 var email_regex = /^([A-Za-z0-9_\-\.\+])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,})$/; 86 87 if ( '' !== email_value && ! email_regex.test( email_value ) ) { 88 add_validation_error( field, field, _wpbc.get_message( 'message_check_email' ) ); 89 } 90 91 return email_value; 92 } 93 94 /** 95 * Validate a confirmation email field using its same_as_NAME class. 96 * 97 * @param {HTMLElement} field Form field. 98 * @param {string} email_value Trimmed confirmation email value. 99 */ 100 function validate_confirmation_email_field( field, email_value ) { 101 var primary_email_match; 102 var primary_email_name; 103 var $primary_email_field; 104 105 if ( field.className.indexOf( 'same_as_' ) === -1 ) { 106 return; 107 } 108 109 primary_email_match = field.className.match( /same_as_([^\s])+/gi ); 110 if ( null === primary_email_match ) { 111 return; 112 } 113 114 primary_email_name = primary_email_match[ 0 ].substr( 8 ); 115 $primary_email_field = $form.find( '[name="' + primary_email_name + resource_id + '"]' ); 116 117 if ( $primary_email_field.length && $primary_email_field.val() !== email_value ) { 118 add_validation_error( field, field, _wpbc.get_message( 'message_check_same_email' ) ); 119 } 120 } 121 122 /** 123 * Validate fields using the validate_as_date, validate_as_digit, or validate_digit_N classes. 124 * 125 * @param {HTMLElement} field Form field. 126 * @param {jQuery} $field Cached jQuery field. 127 */ 128 function validate_custom_field_classes( field, $field ) { 129 var class_list = $field.attr( 'class' ); 130 var field_value; 131 132 if ( ! class_list ) { 133 return; 134 } 135 136 field_value = $field.val(); 137 138 jQuery.each( class_list.split( /\s+/ ), function ( class_index, class_name ) { 139 var digits_to_check; 140 var message;
141 var validation_regex; 142 143 if ( 'validate_as_date' === class_name ) { 144 validation_regex = new RegExp( '^[0-3]?\\d{1}[\\/\\.\\-]+[0-3]?\\d{1}[\\/\\.\\-]+[0-2]+\\d{3}$' ); 145 message = _wpbc.get_message( 'message_check_valid_date' ).replace( '{date_example}', '09/25/2018' ); 146 147 if ( '' !== field_value && ! validation_regex.test( field_value ) ) { 148 add_validation_error( field, field, message ); 149 } 150 return; 151 } 152 153 if ( 'validate_as_digit' === class_name ) { 154 validation_regex = new RegExp( '^[0-9]+\\.?[0-9]*$' ); 155 156 if ( '' !== field_value && ! validation_regex.test( field_value ) ) { 157 add_validation_error( field, field, _wpbc.get_message( 'message_check_digits_only' ) ); 158 } 159 return; 160 } 161 162 if ( 'validate_digit_' !== class_name.substring( 0, 15 ) ) { 163 return; 164 } 165 166 digits_to_check = parseInt( class_name.substring( 15 ), 10 ); 167 if ( isNaN( digits_to_check ) ) { 168 return; 169 } 170 171 validation_regex = new RegExp( '^\\d{' + digits_to_check + '}$' ); 172 message = _wpbc.get_message( 'message_check_digits_count' ).replace( '{digits}', digits_to_check ); 173 174 if ( '' !== field_value && ! validation_regex.test( field_value ) ) { 175 add_validation_error( field, field, message ); 176 } 177 } ); 178 } 179 180 $form.find( ':input' ).each( function () { 181 var field = this; 182 var $field = jQuery( field ); 183 var field_type = $field.attr( 'type' ); 184 var email_value; 185 186 if ( -1 !== skip_element_types.indexOf( field_type ) ) { 187 return; 188 } 189 190 if ( '1' === String( $field.attr( 'data-wpbc-booking-submit-ignore' ) || '' ) ) { 191 return; 192 } 193 194 if ( 195 ( 'date_booking' + resource_id === $field.attr( 'name' ) ) && 196 jQuery( '#calendar_booking' + resource_id ).is( ':visible' ) && 197 ( '' === $field.val() ) && 198 ( 0 === wpbc_get_arr_of_selected_additional_calendars( resource_id ).length ) 199 ) { 200 add_validation_error( 201 null, 202 '#booking_form_div' + resource_id + ' .bk_calendar_frame', 203 _wpbc.get_message( 'message_check_no_selected_dates' ) 204 ); 205 } 206 207 if ( ! $field.is( ':visible' ) ) { 208 return; 209 } 210 211 validate_required_field( field, $field, field_type ); 212 213 if ( $field.hasClass( 'wpdev-validates-as-email' ) ) { 214 email_value = validate_email_field( field, $field ); 215 validate_confirmation_email_field( field, email_value ); 216 } 217 218 validate_custom_field_classes( field, $field ); 219 } ); 220 221 if ( fields_with_errors_arr.length ) { 222 jQuery( fields_with_errors_arr[ 0 ] ).trigger( 'focus' ); 223 } 224 225 return is_error_in_field; 226} 227 228/** 229 * Hint labels inside of input boxes. 230 */ 231jQuery( document ).ready( 232 function () { 233 234 jQuery( 'div.inside_hint' ).on( 235 'click', 236 function () { 237 jQuery( this ).css( 'visibility', 'hidden' ).siblings( '.has-inside-hint' ).trigger( 'focus' ); 238 } 239 ); 240 241 jQuery( 'input.has-inside-hint' ).on( 242 'blur', 243 function () { 244 if ( '' === this.value ) { 245 jQuery( this ).siblings( '.inside_hint' ).css( 'visibility', '' ); 246 } 247 } 248 ).on( 249 'focus', 250 function () { 251 jQuery( this ).siblings( '.inside_hint' ).css( 'visibility', 'hidden' ); 252 } 253 ); 254 255 jQuery( '.booking_form_div input[type=button]' ).prop( "disabled", false ); 256 } 257); 258 259// == WIZARD =========================================================================================================== 260 261/** 262 * Go to next specific step in Wizard style booking form, with 263 * check all required elements specific step, otherwise show warning message! 264 * 265 * @param el 266 * @param step_num 267 * @returns {boolean} 268 */ 269function wpbc_wizard_step(el, step_num, step_from) { 270 271 var br_id = jQuery( el ).closest( 'form' ).find( 'input[name^="bk_type"]' ).val(); 272 273 // FixIn: 8.8.1.5. 274 if ( (undefined == step_from) || (step_num > step_from) ) { 275 if ( 1 != step_num ) { // FixIn: 8.7.7.8. 276 var is_error = wpbc_check_errors_in_booking_form( br_id ); 277 if ( is_error ) { 278 return false; 279 } 280 } 281 } 282 283 if ( wpbc_is_some_elements_visible( br_id, [ 'rangetime', 'durationtime', 'starttime', 'endtime' ] ) ) { 284 if ( wpbc_is_this_time_selection_not_available( br_id, document.getElementById( 'booking_form' + br_id ) ) ) { 285 return false;
286 } 287 } 288 289 if ( br_id != undefined ) { 290 jQuery( "#booking_form" + br_id + " .wpbc_wizard_step" ).css( { "display": "none" } ) 291 .removeClass( 'wpbc_wizard_step_hidden' ); 292 jQuery( "#booking_form" + br_id + " .wpbc_wizard_step" + step_num ).css( { "display": "block" } ); 293 return jQuery( "#booking_form" + br_id + " .wpbc_wizard_step" + step_num ); 294 } 295} 296 297 298/** 299 * Init Buttons in Booking form Wizard 300 */ 301function wpbc_hook__init_booking_form_wizard_buttons() { 302 303 // CSS classes in Wizard Next / Prior links can be like this: <a class="wpbc_button_light wpbc_wizard_step_button wpbc_wizard_step_1">Step 1</a> | <a class="wpbc_button_light wpbc_wizard_step_button wpbc_wizard_step_2">Step 2</a> . 304 305 jQuery( '.wpbc_wizard_step_button' ).attr( 306 { 307 href: 'javascript:void(0)', 308 } 309 ); 310 311 jQuery( '.wpbc_wizard_step_button' ).off( 'click.wpbc_booking_form_wizard' ).on( 312 'click.wpbc_booking_form_wizard', 313 function (event) { 314 var found_steps_arr = jQuery( this ).attr( 'class' ).match( /wpbc\_wizard\_step\_([\d]+)([\s'"]+|$)/ ); 315 316 if ( (null !== found_steps_arr) && (found_steps_arr.length > 2) ) { 317 var step = parseInt( found_steps_arr[1] ); 318 if ( step > 0 ) { 319 var jq_step_element; 320 // Check actual step in booking form for getting step_from number. 321 var this_formsteps_arr = jQuery( this ).parents( '.wpbc_wizard_step' ).attr( 'class' ).match( /wpbc\_wizard\_step([\d]+)([\s'"]+|$)/ ); 322 if ( (null !== this_formsteps_arr) && (this_formsteps_arr.length > 2) ) { 323 var step_from = parseInt( this_formsteps_arr[1] ); 324 jq_step_element = wpbc_wizard_step( this, step, step_from ); 325 } else { 326 jq_step_element = wpbc_wizard_step( this, step ); 327 } 328 // Do Scroll. 329 if ( false !== jq_step_element ) { 330 wpbc_do_scroll( jq_step_element ); // wpbc_do_scroll( jQuery('.wpbc_wizard_step:visible') );. 331 } 332 } 333 } 334 } 335 ); 336} 337 338 339/** 340 * Check if at least one element from array of elements names in booking form visible or not. 341 * Usage Example: if ( wpbc_is_some_elements_visible( br_id, ['rangetime', 'durationtime', 'starttime', 'endtime'] ) 342 * ){ ... } 343 * 344 * @param resource_id 345 * @param elements_names 346 * @returns {boolean} 347 */ 348function wpbc_is_some_elements_visible(resource_id, elements_names) { 349 350 var my_form = jQuery( '#booking_form' + resource_id ); 351 352 if ( ! my_form.length ) { 353 return false; 354 } 355 356 var is_some_elements_visible = false; 357 // Pseudo-selector that get form elements <input , <textarea , <select, <button... 358 my_form.find( ':input' ).each( 359 function (index, el) { 360 361 // Skip some elements. 362 var skip_elements = [ 'hidden', 'button' ]; 363 364 if ( -1 == skip_elements.indexOf( jQuery( el ).attr( 'type' ) ) ) { 365 366 for ( var ei = 0; ei < (elements_names.length - 1); ei++ ) { 367 368 // Check Calendar Dates Selection. 369 if ( (elements_names[ei] + resource_id) == jQuery( el ).attr( 'name' ) ) { 370 371 if ( jQuery( el ).is( ':visible' ) ) { 372 is_some_elements_visible = true; 373 } 374 } 375 } 376 } 377 } 378 ); 379 380 return is_some_elements_visible; 381} 382 383 384jQuery( document ).ready( 385 function () { 386 wpbc_hook__init_booking_form_wizard_buttons(); 387 } 388); 389 390 391// == DAYS_SELECTIONS ================================================================================================== 392 393/** 394 * Get first day of selection 395 * 396 * @param dates 397 * @returns {string|*} 398 */ 399function get_first_day_of_selection(dates) { 400 401 // Multiple days selections 402 if ( dates.indexOf( ',' ) != -1 ){ 403 var dates_array = dates.split( /,\s*/ ); 404 var length = dates_array.length; 405 var element = null; 406 var new_dates_array = []; 407 408 for ( var i = 0; i < length; i++ ){ 409 410 element = dates_array[ i ].split( /\./ ); 411 412 new_dates_array[ new_dates_array.length ] = element[ 2 ] + '.' + element[ 1 ] + '.' + element[ 0 ]; //2013.12.20 413 } 414 new_dates_array.sort(); 415 416 element = new_dates_array[ 0 ].split( /\./ ); 417 418 return element[ 2 ] + '.' + element[ 1 ] + '.' + element[ 0 ]; //20.12.2013 419 } 420 421 // Range days selection 422 if ( dates.indexOf( ' - ' ) != -1 ){ 423 var start_end_date = dates.split( " - " ); 424 return start_end_date[ 0 ]; 425 } 426 427 // Single day selection 428 return dates; //20.12.2013 429} 430 431 432/** 433 * Get last day of selection. 434 * 435 * @param dates 436 * @returns {*|string} 437 */ 438function get_last_day_of_selection(dates) { 439 440 // Multiple days selections 441 if ( dates.indexOf(',') != -1 ){ 442 var dates_array =dates.split(/,\s*/); 443 var length = dates_array.length; 444 var element = null; 445 var new_dates_array = []; 446 447 for (var i = 0; i < length; i++) { 448 449 element = dates_array[i].split(/\./); 450 451 new_dates_array[new_dates_array.length] = element[2]+'.' + element[1]+'.' + element[0]; //2013.12.20 452 } 453 new_dates_array.sort(); 454 455 element = new_dates_array[(new_dates_array.length-1)].split(/\./); 456 457 return element[2]+'.' + element[1]+'.' + element[0]; //20.12.2013 458 } 459 460 // Range days selection 461 if ( dates.indexOf(' - ') != -1 ){ 462 var start_end_date = dates.split(" - "); 463 return start_end_date[(start_end_date.length-1)]; 464 } 465 466 // Single day selection 467 return dates; //20.12.2013 468} 469 470 471/** 472 * Check ID of selected additional calendars 473 * 474 * @param int bk_type 475 * @returns array 476 */
477function wpbc_get_arr_of_selected_additional_calendars( bk_type ){ // FixIn: 8.5.2.26. 478 479 var selected_additionl_calendars = []; 480 481 // Checking according additional calendars 482 if ( document.getElementById( 'additional_calendars' + bk_type ) != null ){ 483 484 var id_additional_str = document.getElementById( 'additional_calendars' + bk_type ).value; 485 var id_additional_arr = id_additional_str.split( ',' ); 486 487 for ( var ia = 0; ia < id_additional_arr.length; ia++ ){ 488 if ( document.getElementById( 'date_booking' + id_additional_arr[ ia ] ).value != '' ){ 489 selected_additionl_calendars.push( id_additional_arr[ ia ] ); 490 } 491 } 492 } 493 return selected_additionl_calendars; 494} 495 496 497// == ELEMENTOR Ready Widget Update ==================================================================================== 498 499jQuery( function ($) { 500 // FixIn: 10.14.15.1. 501 if ( (window.elementorFrontend) && ('undefined' !== typeof (elementorFrontend.hooks)) ) { 502 503 elementorFrontend.hooks.addAction( 'frontend/element_ready/wpbc_widget_booking_form_1.default', function ($scope) { 504 // Simulate DOM ready, after updating Elementor Widget. 505 jQuery( document ).trigger( 'wpbc_elementor_ready' ); 506 } ); 507 508 // Catch all widget re-renders. 509 // elementorFrontend.hooks.addAction( 'frontend/element_ready/global', function ($scope) { 510 // console.log( 'Some widget was re-rendered:', $scope ); 511 // } ); 512 } 513} ); 514 515// Elementor widget reinit. So we need to reinit all "jQuery( document ).ready( ...) " again with custom 'wpbc_elementor_ready' event. 516jQuery( document ).on( 517 'wpbc_elementor_ready', 518 function () { 519 520 wpbc_hook__init_booking_form_wizard_buttons(); 521 522 if ( 'function' === typeof (wpbc_hook__init_timeselector) ) { 523 wpbc_hook__init_timeselector(); 524 } 525 526 if ( 'function' === typeof (wpbc_update_capacity_hint) ) { 527 jQuery( '.booking_form_div' ).on( 528 'wpbc_booking_date_or_option_selected', 529 function (event, resource_id) { 530 wpbc_update_capacity_hint( resource_id ); 531 } 532 ); 533 } 534 535 } 536);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.