PluginProbe
Booking Calendar / trunk
Booking Calendar vtrunk
11.7 11.6.1 11.6 11.5 11.4.3 11.4.2 11.4.1 11.4 11.3 11.2.1 11.2 11.1 11.0 10.15.7 10.15.6 10.1.3 10.10 10.10.1 10.10.2 10.11 10.11.2 10.11.3 10.11.4 10.12.0 10.12.1 All 199 releases
booking / js / client.js

client.js in Booking Calendar trunk, at js/client.js

537 lines 15.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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 */
8 function 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 */
231 jQuery( 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 */
269 function 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 */
301 function 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 */
348 function 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
384 jQuery( 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 */
399 function 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 */
438 function 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 */
477 function 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
499 jQuery( 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.
516 jQuery( 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 );
537