PluginProbe ʕ •ᴥ•ʔ
JetFormBuilder — Dynamic Blocks Form Builder / 2.1.8
JetFormBuilder — Dynamic Blocks Form Builder v2.1.8
3.6.3.1 3.6.3 3.6.2.2 3.6.2.1 3.6.2 3.6.1.1 3.6.1 3.6.0.1 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.3.0 1.3.1 1.3.2 1.3.3 1.4.0 1.4.1 1.4.2 1.4.3 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.1.0 2.1.1 2.1.10 2.1.11 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 3.0.0 3.0.0.1 3.0.0.2 3.0.0.3 3.0.1 3.0.1.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.0.1 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 3.2.0 3.2.1 3.2.2 3.2.3 3.3.0 3.3.1 3.3.2 3.3.3 3.3.3.1 3.3.4 3.3.4.1 3.3.4.2 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.4.5 3.4.5.1 3.4.5.2 3.4.6 3.4.7 3.4.7.1 3.5.0 3.5.1 3.5.1.1 3.5.1.2 3.5.2 3.5.2.1 3.5.3 3.5.4 3.5.5 3.5.6 3.5.6.1 3.5.6.2 3.5.6.3 3.6.0
jetformbuilder / assets / js / frontend-forms.js
jetformbuilder / assets / js Last commit date
admin 3 years ago action-localize-helper.js 3 years ago admin-package.js 3 years ago admin-vuex-package.js 3 years ago editor.js 3 years ago file-upload.js 3 years ago form-block.js 3 years ago frontend-forms.js 3 years ago import-form.js 3 years ago map-field.js 3 years ago package.js 3 years ago re-captcha-v3.js 3 years ago
frontend-forms.js
1793 lines
1 ( function( $ ) {
2
3 'use strict';
4
5 const { addAction, doAction, applyFilters } = wp.hooks;
6
7 const JetFormBuilderDev = {
8 isActive: function() {
9 return Boolean( window.JetFormBuilderSettings.devmode );
10 },
11 log: function( label = '', params = {} ) {
12 if ( ! this.isActive() || ! params ) {
13 return;
14 }
15 console.group( label );
16 for ( const key in params ) {
17 console.log( `${ key }: ${ params[ key ] }` );
18 }
19 console.groupEnd();
20 },
21 hardLog: function( label = '', params = {} ) {
22 this.log( label, params );
23 if ( this.isActive() ) {
24 debugger;
25 }
26 },
27 }
28
29 window.JetFormBuilderMain = {
30
31 filters: ( function() {
32
33 var callbacks = {};
34
35 return {
36
37 addFilter: function( name, callback ) {
38
39 if ( ! callbacks.hasOwnProperty( name ) ) {
40 callbacks[ name ] = [];
41 }
42
43 callbacks[ name ].push( callback );
44
45 },
46
47 applyFilters: function( name, value, args ) {
48
49 if ( ! callbacks.hasOwnProperty( name ) ) {
50 return value;
51 }
52
53 if ( args === undefined ) {
54 args = [];
55 }
56
57 var container = callbacks[ name ];
58 var cbLen = container.length;
59
60 for ( var i = 0; i < cbLen; i++ ) {
61 if ( typeof container[ i ] === 'function' ) {
62 value = container[ i ]( value, args );
63 }
64 }
65
66 return value;
67 },
68
69 };
70
71 } )(),
72
73 };
74
75 $.fn.jetFormBuilderConditional = function( options ) {
76
77 this.JFBroot = this.closest( '.jet-form-builder-repeater__row-fields' );
78
79 if ( ! this.JFBroot.length ) {
80 this.JFBroot = this.closest( 'form.jet-form-builder' );
81 } else {
82 this.JFBparent = this.closest( 'form.jet-form-builder' );
83 }
84
85 const current = this;
86
87 var settings = $.extend( {
88 hideJS: true,
89 }, options );
90
91 var checkValue = function( $listenTo, listenFor, operator ) {
92
93 var val = '';
94 var checkResult = false;
95 var controlType = 'plain';
96
97 operator = operator || 'equal';
98
99 if ( $listenTo.is( 'input[type=checkbox]' ) ) {
100 controlType = 'checkbox';
101 } else if ( $listenTo.is( 'input[type=radio]' ) ) {
102 controlType = 'radio';
103 }
104
105 if ( 'checkbox' === controlType ) {
106 val = [];
107 }
108
109 if ( 'plain' === controlType ) {
110 val = $listenTo.val();
111 } else {
112
113 $listenTo.each( function() {
114
115 var $control = $( this );
116
117 if ( $control.is( ':checked' ) ) {
118 if ( 'checkbox' === controlType ) {
119 val.push( $control.val() );
120 } else {
121 val = $control.val();
122 }
123 }
124
125 } );
126 }
127
128 switch ( operator ) {
129 case 'equal':
130 if ( val && val.constructor === Array ) {
131 checkResult = false;
132 } else {
133 checkResult = ( val == listenFor );
134 }
135 break;
136
137 case 'greater':
138 if ( val && val.constructor === Array ) {
139 checkResult = false;
140 } else {
141 checkResult = ( parseFloat( val ) > parseFloat( listenFor ) );
142 }
143 break;
144
145 case 'less':
146 if ( val && val.constructor === Array ) {
147 checkResult = false;
148 } else {
149 checkResult = ( parseFloat( val ) < parseFloat( listenFor ) );
150 }
151 break;
152
153 case 'between':
154
155 if ( val && val.constructor === Array ) {
156 checkResult = false;
157 } else {
158 if ( 2 <= listenFor.length ) {
159 let from = parseFloat( listenFor[ 0 ] );
160 let to = parseFloat( listenFor[ 1 ] );
161 val = parseFloat( val );
162 checkResult = ( from <= val && val <= to );
163 } else {
164 checkResult = false;
165 }
166 }
167
168 break;
169
170 case 'one_of':
171 if ( val && val.constructor === Array ) {
172 checkResult = false;
173
174 for ( const valElement of val ) {
175 if ( listenFor.length && 0 <= listenFor.indexOf( valElement ) ) {
176 checkResult = true;
177 }
178 }
179
180 } else if ( ! val ) {
181 checkResult = false;
182 } else {
183 if ( listenFor.length ) {
184 checkResult = 0 <= listenFor.indexOf( val );
185 } else {
186 checkResult = false;
187 }
188 }
189
190 break;
191
192 case 'contain':
193 if ( val && val.constructor === Array ) {
194
195 var intersect = val.filter( function( n ) {
196 return n.indexOf( listenFor ) !== -1;
197 } );
198
199 checkResult = 0 < intersect.length;
200
201 } else if ( ! val ) {
202 checkResult = false;
203 } else {
204 checkResult = 0 <= val.indexOf( listenFor );
205 }
206
207 break;
208 }
209
210 return checkResult;
211 };
212
213 var checkVisibilityCond = ( listenTo, listenFor, $section, operator, type ) => {
214
215 let $listenTo = $( listenTo, current.JFBroot );
216
217 if ( ! $listenTo.length && current?.JFBparent?.length ) {
218 $listenTo = $( listenTo, current.JFBparent );
219 }
220
221 var checkResult = checkValue( $listenTo, listenFor, operator );
222
223 type = type || 'show';
224
225 $section.JFBchecked = $section.JFBchecked ?? {};
226
227 if ( 'show' === type ) {
228 $section.JFBchecked[ listenTo ] = checkResult;
229 } else {
230 $section.JFBchecked[ listenTo ] = ! checkResult;
231 }
232 };
233
234 var checkSetValueCond = function( listenTo, listenFor, $section, operator, value, type ) {
235
236 var currentVal = $section.data( 'result_' + type );
237 var $listenTo = $( listenTo );
238 var checkResult = checkValue( $listenTo, listenFor, operator );
239
240 if ( checkResult ) {
241 currentVal = value;
242 }
243
244 $section.data( 'result_' + type, currentVal );
245
246 };
247
248 var setValue = function( $section ) {
249
250 var setVal = false;
251 var setCalcVal = false;
252 var $field;
253 var triggered = false;
254
255 if ( $section.data( 'result_set_value' ) ) {
256 setVal = $section.data( 'result_set_value' );
257 }
258
259 if ( $section.data( 'result_set_calculated_value' ) ) {
260 setCalcVal = $section.data( 'result_set_calculated_value' );
261 }
262
263 if ( ! setVal && ! setCalcVal ) {
264 return;
265 }
266
267 $field = $section.find( '.jet-form-builder__field' );
268
269 if ( ! $field.length ) {
270 return;
271 }
272
273 if ( $field.is( 'select' ) ) {
274
275 $field.find( ':selected' ).removeAttr( 'selected' );
276
277 if ( setVal ) {
278 $field.find( 'option[value="' + setVal + '"]' ).attr( 'selected', 'selected' ).trigger( 'change.JetFormBuilderMain' );
279 triggered = true;
280 }
281
282 if ( setCalcVal ) {
283 $field.find( 'option[data-calculate="' + setCalcVal + '"]' ).attr( 'selected', 'selected' );
284 if ( ! triggered ) {
285 $field.trigger( 'change.JetFormBuilderMain' );
286 triggered = true;
287 }
288 }
289
290 } else if ( $field.is( ':not( input[type=checkbox], input[type=radio] )' ) ) {
291
292 if ( setVal ) {
293 $field.val( setVal ).trigger( 'change.JetFormBuilderMain' );
294 triggered = true;
295 }
296
297 if ( setCalcVal ) {
298 $field.data( 'calculate', setCalcVal );
299 if ( ! triggered ) {
300 $field.trigger( 'change.JetFormBuilderMain' );
301 triggered = true;
302 }
303 }
304
305 } else {
306
307 $field.each( function() {
308
309 var $this = $( this );
310
311 if ( $this.is( ':checked' ) ) {
312 $this.removeAttr( 'checked' );
313 }
314
315 if ( setVal && setVal == $this.val() ) {
316 $this.attr( 'checked', 'checked' ).trigger( 'change.JetFormBuilderMain' );
317 triggered = true;
318 }
319
320 if ( setCalcVal && setCalcVal == $this.data( 'calculate' ) ) {
321 $this.attr( 'checked', 'checked' );
322 if ( ! triggered ) {
323 $this.trigger( 'change.JetFormBuilderMain' );
324 triggered = true;
325 }
326 }
327
328 } );
329
330 }
331
332 };
333
334 var setVisibility = $section => {
335 //var $row = $section.closest( '.jet-form-builder-row' );
336 let res = true;
337
338 if ( ! Object.keys( $section?.JFBchecked ?? {} )?.length ) {
339 return;
340 }
341
342 for ( let check in $section.JFBchecked ) {
343 if ( ! $section.JFBchecked[ check ] ) {
344 res = false;
345 }
346 }
347
348 if ( res ) {
349
350 $section.show();
351 //$row.show();
352
353 $section.find( '*[data-initial-type]' ).each( function() {
354 var $this = $( this );
355
356 $this.attr( 'type', $this.data( 'initial-type' ) );
357 } );
358
359 $section.find( 'select option[data-is-hidden="1"]' ).remove();
360
361 $section
362 .find( '*[data-required="1"]' )
363 .attr( 'required', 'required' );
364
365 } else {
366
367 $section.hide();
368
369 $section.find( '*[type="date"],*[type="time"],*[type="email"],*[type="url"]' ).each( function() {
370 var $this = $( this ),
371 type = $this.attr( 'type' );
372
373 $this.attr( 'data-initial-type', type );
374 $this.attr( 'type', 'text' );
375 } );
376
377 var $select = $section.find( 'select' );
378
379 if ( $select.length ) {
380 $select.append( '<option value="" data-is-hidden="1"></option>' );
381 }
382
383 $section.find( '*[required]' )
384 .removeAttr( 'required' )
385 .attr( 'data-required', 1 );
386
387 /*var $hiddenItems = $row.find( '>*' ).filter( function() {
388 return $( this ).css( 'display' ) === 'none';
389 } );
390
391 if ( $row.find( '>*' ).length === $hiddenItems.length ) {
392 $row.hide();
393 }*/
394 }
395
396 };
397
398 return this.each( function() {
399
400 var $section = $( this );
401 var conditions = $section.data( 'conditional' );
402
403 if ( ! conditions || ! conditions.length ) {
404 return;
405 }
406
407 for ( var i = 0; i < conditions.length; i++ ) {
408
409 let condition = conditions[ i ];
410
411 if ( ! condition.field ) {
412 continue;
413 }
414
415 let listenTo = '[data-field-name=' + condition.field + ']';
416 let listenFor = condition.value;
417 let operator = condition.operator;
418 let type = condition.type;
419 let valueToSet = condition.set_value;
420
421 let field = current.JFBroot.find( listenTo );
422
423 if ( ! field?.length && current?.JFBparent?.length ) {
424 field = current.JFBparent.find( listenTo );
425 }
426
427 field.each( function() {
428 $( this ).on( 'change.JetFormBuilderMain', function() {
429 if ( 'show' === type || 'hide' === type ) {
430 checkVisibilityCond( listenTo, listenFor, $section, operator, type );
431 } else {
432 checkSetValueCond( listenTo, listenFor, $section, operator, valueToSet, type );
433 }
434
435 setValue( $section );
436 setVisibility( $section );
437 });
438 } );
439
440 //If setting was chosen, hide everything first...
441 if ( settings.hideJS && ( 'show' === type || 'hide' === type ) ) {
442 $section.hide();
443 }
444
445 //Show based on current value on page load
446 if ( 'show' === type || 'hide' === type ) {
447 checkVisibilityCond( listenTo, listenFor, $section, operator, type );
448 } else {
449 checkSetValueCond( listenTo, listenFor, $section, operator, valueToSet, type );
450 }
451
452 }
453
454 setValue( $section );
455 setVisibility( $section );
456 } );
457 };
458
459 var JetFormBuilder = {
460
461 pages: {},
462 calcFields: {},
463 repeaterCalcFields: {},
464 childrenCalcFields: {},
465 currentFieldWithError: {
466 length: 0,
467 },
468 initCommon: function( $scope = false ) {
469 let wrappers = $( '.jet-fb-form-block', $scope );
470
471 wrappers.each( function( index, value ) {
472 JetFormBuilder.widgetBookingForm( $( value ) );
473 } );
474 },
475
476 initElementor: function() {
477 const widgets = {
478 'jet-engine-booking-form.default': JetFormBuilder.widgetBookingForm,
479 'jet-form-builder-form.default': JetFormBuilder.widgetBookingForm,
480 };
481
482 $.each( widgets, function( widget, callback ) {
483 window.elementorFrontend.hooks.addAction( 'frontend/element_ready/' + widget, callback );
484 } );
485 },
486
487 addHandlersInit: function() {
488 var self = JetFormBuilder;
489
490 $( document )
491 .on( 'submit.JetFormBuilderMain', 'form.jet-form-builder.submit-type-ajax', self.ajaxSubmitForm )
492 .on( 'submit.JetFormBuilderMain', 'form.jet-form-builder.submit-type-reload', self.reloadSubmitForm )
493 .on( 'click.JetFormBuilderMain', '.jet-form-builder__next-page', self.nextFormPage )
494 .on( 'click.JetFormBuilderMain', '.jet-form-builder__prev-page', self.prevFormPage )
495 .on( 'focus.JetFormBuilderMain', '.jet-form-builder__field', self.clearFieldErrors )
496 .on( 'click.JetFormBuilderMain', '.jet-form-builder__field-template', self.simLabelClick )
497 .on( 'change.JetFormBuilderMain', '.jet-form-builder__field', self.recalcFields )
498 .on( 'change.JetFormBuilderMain', '.jet-form-builder__field', self.maybeInitSinglePage )
499 .on( 'jet-form-builder/repeater-changed', '.jet-form-builder-repeater', self.recalcFields )
500 .on( 'change.JetFormBuilderMain', '.jet-form-builder__field.checkboxes-group-required', self.requiredCheckboxGroup )
501 .on( 'change.JetFormBuilderMain', '.checkradio-field', self.changeActiveTemplateClass )
502 .on( 'input.JetFormBuilderMain/range', '.jet-form-builder__field.range-field', self.updateRangeField )
503 .on( 'click.JetFormBuilderMain', '.jet-form-builder-repeater__new', self.newRepeaterItem )
504 .on( 'click.JetFormBuilderMain', '.jet-form-builder-repeater__remove', self.removeRepeaterItem )
505 .on( 'jet-form-builder/page/field-changed', self.maybeSwitchPage )
506 .on( 'jet-form-builder/switch-page', self.updateProgress )
507 .on( 'input.JetFormBuilderMain', '.jet-form-builder__field.text-field, .jet-form-builder__field.textarea-field', self.inputTextFields )
508 },
509
510 maybeInitSinglePage: function () {
511 const self = $( this ),
512 $page = self.closest( '.jet-form-builder-page' );
513
514 if ( ! $page.length ) {
515 return
516 }
517
518 JetFormBuilder.initSingleFormPage( $page, self );
519 },
520
521 inputTextFields: function() {
522 $( this ).trigger( 'change.JetFormBuilderMain' );
523 },
524
525 updateProgress: function( event, $fromPage, $toPage, $progress ) {
526 if ( ! $progress || 'default' !== $progress.data( 'type' ) ) {
527 return;
528 }
529 const [ from, to ] = [ $fromPage.data( 'page' ), $toPage.data( 'page' ) ];
530
531 const prevItem = $progress.find( `.jet-form-builder-progress-pages__item--wrapper[data-page="${ from }"]` );
532 const currentItem = $progress.find( `.jet-form-builder-progress-pages__item--wrapper[data-page="${ to }"]` );
533
534 prevItem.removeClass( 'active-page' );
535 currentItem.addClass( 'active-page' );
536 currentItem.removeClass( 'passed-page' );
537
538 if ( from < to ) {
539 prevItem.addClass( 'passed-page' );
540 } else {
541 prevItem.removeClass( 'passed-page' );
542 }
543 },
544
545 removeRepeaterItem: function() {
546
547 let $this = $( this ),
548 $repeater = $this.closest( '.jet-form-builder-repeater' ),
549 $repeaterItem = $this.closest( '.jet-form-builder-repeater__row' ),
550 $editor = $repeaterItem.find( '.wp-editor-area' );
551
552 $this.trigger( 'jet-form-builder/on-remove-repeater-item' );
553
554 if ( $editor.length && window.wp && window.wp.editor ) {
555 window.wp.editor.remove( $editor.attr( 'id' ) );
556 }
557
558 $repeaterItem.remove();
559 $repeater.trigger( 'jet-form-builder/repeater-changed' );
560
561 },
562
563 newRepeaterItem: function() {
564 var $this = $( this ),
565 $repeater = $this.closest( '.jet-form-builder-repeater' ),
566 $initial = $repeater.find( '.jet-form-builder-repeater__initial' ),
567 $items = $repeater.find( '.jet-form-builder-repeater__items' ),
568 $newVal = $initial.html(),
569 index = 0;
570
571 if ( $items.find( '.jet-form-builder-repeater__row' ).length ) {
572 $items.find( '.jet-form-builder-repeater__row' ).each( function() {
573 var $this = $( this ),
574 currentIndex = parseInt( $this.data( 'index' ), 10 );
575
576 if ( currentIndex > index ) {
577 index = currentIndex;
578 }
579 } );
580 index++;
581 }
582
583 $newVal = $newVal.replace( /__i__/g, index );
584 $newVal = $( $newVal );
585 $newVal.data( 'index', index );
586 $newVal.attr( 'data-index', index );
587
588 JetFormBuilder.initRangeFields( $newVal );
589
590 $items.append( $newVal );
591
592 var $editors = $newVal.find( '.wp-editor-area' );
593
594 if ( $editors.length && window.wp && window.wp.editor ) {
595 $editors.each( function() {
596 JetFormBuilder.wysiwygInitWithTriggers( this, true );
597 } );
598 }
599
600 if ( $.fn.inputmask ) {
601 $newVal.find( '.jet-form-builder__masked-field' ).inputmask();
602 }
603
604 $repeater.trigger( 'jet-form-builder/repeater-changed' );
605 $this.trigger( 'jet-form-builder/repeater-add-new', [ index ] );
606
607 JetFormBuilder.calculateRowValue( $newVal );
608 JetFormBuilder.initConditions( $newVal );
609
610 },
611
612 updateRepeaterItems: function( $repeater, $field ) {
613
614 var val = JetFormBuilder.getFieldValue( $field );
615
616 if ( ! val ) {
617 return;
618 }
619
620 for ( var i = 0; i < val; i++ ) {
621
622 var $item = $repeater.find( '.jet-form-builder-repeater__row[data-index="' + i + '"]' );
623
624 if ( ! $item.length ) {
625 JetFormBuilder.newRepeaterItem.call( $repeater );
626 }
627
628 }
629
630 var $rows = $repeater.find( '.jet-form-builder-repeater__row' );
631
632 if ( $rows.length ) {
633 $rows.each( function() {
634 var $row = $( this ),
635 index = parseInt( $row.data( 'index' ), 10 );
636
637 index++;
638
639 if ( index > val ) {
640 $row.remove();
641 $repeater.trigger( 'jet-form-builder/repeater-changed' );
642 }
643
644 } );
645 }
646
647 $repeater.trigger( 'change' );
648
649 },
650
651 calculateRowValue: function( $row ) {
652
653 var val = JetFormBuilder.calculateValue( $row );
654
655 $row.data( 'value', val );
656 JetFormBuilder.calculateFieldsInRow( $row );
657
658 },
659
660 calculateFieldsInRow: function( $row ) {
661
662 $row.find( '.jet-form-builder__calculated-field--child' ).each( function() {
663
664 var $childCalculatedField = $( this ),
665 val = JetFormBuilder.calculateValue( $childCalculatedField )
666
667 if ( ! val ) {
668 val = 0;
669 }
670
671 JetFormBuilder.setCalculatedValue( val, $childCalculatedField );
672 } );
673
674 },
675
676 initRepeaterListener: function( $scope ) {
677
678 var $repeater = $scope.find( '.jet-form-builder-repeater' );
679
680 if ( ! $repeater.length ) {
681 return;
682 }
683
684 $repeater.each( function() {
685
686 var $this = $( this ),
687 settings = $this.data( 'settings' );
688
689 if ( 'dynamically' === settings.manageItems && settings.itemsField ) {
690 var $itemsField = $scope.find( '[data-field-name="' + settings.itemsField + '"]' );
691
692 JetFormBuilder.updateRepeaterItems( $this, $itemsField );
693
694 $itemsField.on( 'change', function() {
695 JetFormBuilder.updateRepeaterItems( $this, $itemsField );
696 } );
697 }
698
699 if ( 'custom' === settings.calcType ) {
700
701 var calculated = null;
702
703 JetFormBuilder.repeaterCalcFields[ $this.data( 'field-name' ) ] = {
704 'el': $this,
705 'listenTo': $this.data( 'listen_fields' ),
706 };
707
708 calculated = JetFormBuilder.calculateValue( $this );
709
710 $this.data( 'value', calculated.toFixed( 0 ) );
711
712 }
713
714 var $initial = $this.find( '.jet-form-builder-repeater__initial' );
715 $initial = $( $initial.html() );
716
717 var $calcFields = $initial.find( '.jet-form-builder__calculated-field--child' );
718
719 if ( $calcFields.length ) {
720
721 $calcFields.each( function() {
722
723 var $childField = $( this );
724
725 JetFormBuilder.childrenCalcFields[ $childField.data( 'name' ) ] = {
726 'el': $childField,
727 'parentEl': $this,
728 'listenTo': $childField.data( 'listen_to' ),
729 };
730
731 $this.find( '.jet-form-builder-repeater__row' ).each( function() {
732 JetFormBuilder.calculateRowValue( $( this ), $childField.data( 'precision' ) );
733 } );
734
735 } );
736 }
737
738 } );
739
740 },
741
742 simLabelClick: function( event ) {
743 $( this ).next( '.jet-form-builder__field-label' ).trigger( 'click' );
744 },
745
746 maybeSwitchPage: function( event, $field, $page, disabled ) {
747
748 var $item = $field[ 0 ],
749 isSwitch = $field.data( 'switch' ),
750 value = null,
751 $toPage = null;
752
753 if ( ! isSwitch ) {
754 return;
755 }
756
757 if ( disabled ) {
758 return;
759 }
760
761 value = $item.value;
762
763 if ( ! value ) {
764 return;
765 }
766
767 $toPage = $page.next();
768
769 if ( ! $page || ! $page.length ) {
770 return;
771 }
772
773 if ( ! $toPage || ! $toPage.length ) {
774 return;
775 }
776
777 JetFormBuilder.switchFormPage( $page, $toPage );
778
779 },
780
781 changeActiveTemplateClass: function( event ) {
782
783 var $this = $( this ),
784 $template = $this.closest( '.jet-form-builder__field-wrap' ).find( '.jet-form-builder__field-template' );
785
786 if ( ! $template.length ) {
787 return;
788 }
789
790 if ( 'radio' === $this[ 0 ].type ) {
791 $template
792 .closest( '.jet-form-builder__fields-group' )
793 .find( '.jet-form-builder__field-template--checked' )
794 .removeClass( 'jet-form-builder__field-template--checked' );
795 }
796
797 $template.toggleClass( 'jet-form-builder__field-template--checked', $this[ 0 ].checked );
798
799 },
800
801 initConditions: function( $scope ) {
802 $scope.find( '.jet-form-builder__conditional' ).jetFormBuilderConditional();
803 },
804 widgetBookingForm: function( $scope ) {
805 var $editors = $scope.find( '.jet-form-builder__field .wp-editor-area' );
806
807 if ( $editors.length && window.wp && window.wp.editor ) {
808 $editors.each( function() {
809 JetFormBuilder.wysiwygInitWithTriggers( this, true );
810 } );
811 }
812 JetFormBuilder.initRequiredCheckboxGroup( $scope );
813
814 $( document ).trigger( 'jet-form-builder/init', [ $scope ] );
815
816 JetFormBuilder.initFormPager( $scope );
817 JetFormBuilder.initRangeFields( $scope );
818 JetFormBuilder.initRepeaterListener( $scope );
819 JetFormBuilder.initConditions( $scope );
820
821 if ( $.fn.inputmask ) {
822 $scope.find( '.jet-form-builder__masked-field' ).inputmask();
823 }
824 JetFormBuilder.initCalcFields( $scope );
825 JetFormBuilder.initReplaceValues( $scope );
826
827 $( document ).trigger( 'jet-form-builder/after-init', [ $scope ] );
828 },
829
830 initCalcFields: function( $scope ) {
831 const $calcFields = $scope.find( '.jet-form-builder__calculated-field' );
832
833 if ( ! $calcFields.length ) {
834 return;
835 }
836
837 $( $calcFields ).each( function() {
838
839 var $this = $( this ),
840 calculated = null;
841
842 JetFormBuilder.calcFields[ $this.data( 'name' ) ] = {
843 'el': $this,
844 'listenTo': $this.data( 'listen_to' ),
845 };
846
847 calculated = JetFormBuilder.calculateValue( $this );
848
849 JetFormBuilder.setCalculatedValue( calculated, $this );
850 } );
851 },
852
853 initReplaceValues: function( $scope ) {
854 const $form = $scope.find( 'form.jet-form-builder' );
855
856 const macrosPrefix = ( suffix = '' ) => 'JFB_FIELD::' + suffix;
857
858 const replaceAttrs = window.JetFormBuilderSettings.replaceAttrs || [];
859 JetFormBuilder.replaceStack = JetFormBuilder.replaceStack || {};
860
861 const getAllComments = rootElem => {
862 const comments = [];
863 // Fourth argument, which is actually obsolete according to the DOM4 standard, is required in IE 11
864 const iterator = document.createNodeIterator( rootElem, NodeFilter.SHOW_COMMENT, () => NodeFilter.FILTER_ACCEPT, false );
865 let curNode;
866
867 const timestamp = Date.now();
868 let counter = 0;
869
870 const uniqId = () => {
871 return ++counter + '_' + timestamp;
872 }
873
874 while ( curNode = iterator.nextNode() ) {
875 if ( curNode.textContent.includes( macrosPrefix() ) ) {
876 curNode.nodeValue = curNode.nodeValue.trim();
877
878 comments.push( { id: uniqId(), node: curNode } );
879 }
880 }
881 const querySelector = [];
882
883 for ( let i = 0; i < replaceAttrs.length; i++ ) {
884 querySelector.push( `[${ replaceAttrs[ i ] }*="${ macrosPrefix() }"]` );
885 }
886
887 const elements = Array.from( rootElem.querySelectorAll( querySelector.join( ', ' ) ) );
888
889 elements.forEach( elem => {
890 for ( let i = 0; i < replaceAttrs.length; i++ ) {
891 const attr = elem[ replaceAttrs[ i ] ] || "";
892
893 if ( ! attr.toLowerCase().includes( macrosPrefix().toLowerCase() ) ) {
894 continue;
895 }
896
897 comments.push( {
898 id: uniqId(),
899 attr: replaceAttrs[ i ],
900 value: decodeURIComponent( attr ),
901 node: elem,
902 } );
903 }
904 } )
905
906 return comments;
907 }
908
909 const isRadio = function( $field ) {
910 if ( 'INPUT' !== $field.prop( 'tagName' ) ) {
911 return false;
912 }
913
914 return [ 'checkbox', 'radio' ].includes( $field.attr( 'type' ) );
915 }
916
917 const getFieldNamesWithBrackets = macrosValue => {
918 const matches = macrosValue.match( /(?:<!\-{2}\s*JFB_FIELD::)([\w\-]+)\s*(?:\-{2}>)/gi );
919
920 if ( ! matches ) {
921 return [];
922 }
923
924 return matches.map(
925 match => match.replace( /<!\-{2}\s*JFB_FIELD::/gi, '' ).replace( /\-{2}>/gi, '' )
926 )
927 };
928
929 const getFieldNamesWithOutBrackets = macrosValue => {
930 const matches = macrosValue.match( /(?:\s*JFB_FIELD::)([\w\-]+)\s*/gi );
931
932 if ( ! matches ) {
933 return [];
934 }
935
936 return matches.map(
937 match => match.replace( /\s*JFB_FIELD::/gi, '' )
938 )
939 };
940
941 const getFieldNames = ( macrosValue, withBrackets = true ) => {
942 return withBrackets
943 ? getFieldNamesWithBrackets( macrosValue )
944 : getFieldNamesWithOutBrackets( macrosValue );
945 };
946
947 const replaceMacros = ( replaceFrom, fieldName, fieldValue, withBrackets = true ) => {
948 const regExp = withBrackets
949 ? new RegExp( `<!--\\s*JFB_FIELD::${ fieldName }\\s*-->`, 'gi' )
950 : new RegExp( `\\s*JFB_FIELD::${ fieldName }\\s*`, 'gi' );
951
952 return replaceFrom.replace( regExp, fieldValue );
953 };
954
955 const getValueFromField = field => {
956 const is_radio = isRadio( field );
957
958 if ( ! is_radio ) {
959 return field.val();
960 }
961
962 const checked = [];
963 for ( const radioInput of Array.from( field ) ) {
964 if ( radioInput.checked ) {
965 checked.push( radioInput.value );
966 }
967 }
968
969 return checked.join( ', ' );
970 }
971
972 const prepareValueFromMacros = function( scope, initialValue, withBrackets = true ) {
973 const fieldNames = getFieldNames( initialValue, withBrackets );
974
975 fieldNames.forEach( name => {
976 const fieldElement = scope.find( `[data-field-name="${ name }"]` );
977
978 let fieldValue = applyFilters(
979 'jet.fb.macro.field.value',
980 false,
981 fieldElement,
982 scope,
983 )
984
985 if ( false === fieldValue ) {
986 fieldValue = getValueFromField( fieldElement );
987 }
988
989 initialValue = replaceMacros( initialValue, name, fieldValue, withBrackets );
990 } );
991
992 return initialValue;
993 }
994
995 const replaceAttr = ( macros, scope ) => {
996 const replacement = prepareValueFromMacros( scope, macros.value );
997
998 if ( replacement !== macros.node[ macros.attr ] ) {
999 macros.node[ macros.attr ] = replacement;
1000 }
1001 };
1002
1003 const insertText = ( macros, scope ) => {
1004 let currentValue = prepareValueFromMacros( scope, macros.node.nodeValue, false );
1005
1006 let prevSibling = Array.from( macros.node.parentNode.childNodes ).find(
1007 node => node.JFB_macros_id === macros.id,
1008 );
1009
1010 if ( ! prevSibling ) {
1011 let wrapper = document.createElement( 'span' );
1012 wrapper.innerHTML = currentValue;
1013
1014 prevSibling = macros.node.parentNode.insertBefore( wrapper, macros.node );
1015 prevSibling.JFB_macros_id = macros.id;
1016
1017 return;
1018 }
1019
1020 if ( prevSibling.innerHTML === currentValue ) {
1021 return;
1022 }
1023
1024 prevSibling.innerHTML = currentValue;
1025 };
1026
1027 const replaceFieldValues = scope => {
1028 const currentFormId = scope.data( 'form-id' );
1029
1030 for ( const formID in JetFormBuilder.replaceStack ) {
1031 if ( +formID !== currentFormId ) {
1032 continue;
1033 }
1034 const multiMacros = JetFormBuilder.replaceStack[ currentFormId ].macros;
1035
1036 multiMacros.forEach( macros => {
1037 if ( macros.attr ) {
1038 replaceAttr( macros, scope );
1039 } else if ( macros.node.nodeName === '#comment' ) {
1040 insertText( macros, scope );
1041 }
1042 } );
1043 }
1044 };
1045
1046 const initRepeater = function( e ) {
1047 const repeater = $( e.target ).closest( '.jet-form-builder-repeater' );
1048 const $form = $( e.target ).closest( 'form.jet-form-builder' );
1049
1050 const formID = $form.data( 'form-id' );
1051 const repeaterName = repeater.data( 'field-name' );
1052
1053 let repeaterRowsList = JetFormBuilder.replaceStack[ formID ].repeaters[ repeaterName ] || [];
1054 let [ scope ] = $( '.jet-form-builder-repeater__row:last', repeater );
1055
1056 if ( ! repeaterRowsList.includes( +scope.dataset.index ) ) {
1057 pushRepeaterRowIndex( formID, repeaterName, +scope.dataset.index );
1058 pushStack( formID, getAllComments( scope ) );
1059 }
1060
1061 replaceFieldValues( $form );
1062 }
1063
1064 const pushStack = function( formId, stack ) {
1065 JetFormBuilder.replaceStack[ formId ].macros.push( ...stack );
1066 };
1067
1068 const pushRepeaterRowIndex = function( formId, repeaterName, index ) {
1069 const repeater = JetFormBuilder.replaceStack[ formId ].repeaters[ repeaterName ] || [];
1070 repeater.push( index );
1071
1072 JetFormBuilder.replaceStack[ formId ].repeaters[ repeaterName ] = repeater;
1073 }
1074
1075 $( document ).on( 'change.JetFormBuilderMain', 'form.jet-form-builder .jet-form-builder__field', function() {
1076 replaceFieldValues( $( this ).closest( 'form.jet-form-builder' ) );
1077 } );
1078
1079 if ( $form.length ) {
1080 JetFormBuilder.replaceStack[ $form.data( 'form-id' ) ] = {
1081 macros: [],
1082 repeaters: {},
1083 };
1084 pushStack( $form.data( 'form-id' ), getAllComments( $form[ 0 ] ) );
1085 replaceFieldValues( $form );
1086 }
1087
1088 $( document ).on(
1089 'jet-form-builder/repeater-add-new',
1090 '.jet-form-builder-repeater__new',
1091 e => initRepeater( e ),
1092 );
1093 },
1094
1095 initFormPager: function( $scope ) {
1096 var $pages = $scope.find( '.jet-form-builder-page' ),
1097 $form = $scope.find( '.jet-form-builder' );
1098
1099 if ( ! $pages.length ) {
1100 return;
1101 }
1102
1103 $pages.each( function() {
1104
1105 var $page = $( this );
1106
1107 if ( ! $page.hasClass( '.jet-form-builder-page--hidden' ) ) {
1108 JetFormBuilder.initSingleFormPage( $page, false );
1109 }
1110
1111 } );
1112
1113 },
1114
1115 initSingleFormPage: function( $page, $changedField ) {
1116 let $msg = $page.find( '.jet-form-builder__next-page-msg' ),
1117 requiredFields = $page[ 0 ].querySelectorAll( '.jet-form-builder__field[required]' ),
1118 disabled = false,
1119 radioFields = {};
1120
1121 $changedField = $changedField || false;
1122
1123 if ( requiredFields.length ) {
1124 for ( var i = 0; i < requiredFields.length; i++ ) {
1125
1126 var $field = $( requiredFields[ i ] );
1127 var val = null;
1128 var isRadio = false;
1129
1130 if ( 'INPUT' === $field[ 0 ].nodeName ) {
1131
1132 if ( $field.length > 1 ) {
1133 for ( var j = 0; j < $field.length; j++ ) {
1134 if ( $field[ j ].checked ) {
1135 val = $field[ j ].value;
1136 }
1137 }
1138 } else if ( 'radio' === $field[ 0 ].type ) {
1139
1140 isRadio = true;
1141
1142 if ( $field[ 0 ].checked ) {
1143 radioFields[ $field[ 0 ].name ] = $field[ 0 ].value;
1144 }
1145
1146 } else {
1147 val = $field.val();
1148 }
1149 }
1150
1151 if ( 'TEXTAREA' === $field[ 0 ].nodeName ) {
1152 val = $field.val();
1153 }
1154
1155 if ( 'SELECT' === $field[ 0 ].nodeName ) {
1156 val = $field.find( 'option:selected' ).val();
1157 }
1158
1159 if ( ! val ) {
1160 disabled = true;
1161 }
1162
1163 if ( isRadio && radioFields[ $field[ 0 ].name ] ) {
1164 disabled = false;
1165 }
1166
1167 }
1168 }
1169
1170 if ( disabled && $msg.length ) {
1171 $msg.addClass( 'jet-form-builder__next-page-msg--visible' );
1172
1173 } else if ( $msg.length ) {
1174 $msg.removeClass( 'jet-form-builder__next-page-msg--visible' );
1175 }
1176
1177 if ( $changedField ) {
1178 $( document ).trigger( 'jet-form-builder/page/field-changed', [ $changedField, $page, disabled ] );
1179 }
1180
1181 return disabled;
1182 },
1183
1184 nextFormPage: function() {
1185
1186 var $button = $( this ),
1187 $fromPage = $button.closest( '.jet-form-builder-page' ),
1188 $pageFields = $fromPage.find( '.jet-form-builder__field' ).filter( ':input' ),
1189 $toPage = $fromPage.next();
1190
1191 if (
1192 ! JetFormBuilder.isFieldsValid( $pageFields ) ||
1193 JetFormBuilder.initSingleFormPage( $fromPage, false )
1194 ) {
1195 return;
1196 }
1197
1198 JetFormBuilder.switchFormPage( $fromPage, $toPage );
1199
1200 },
1201
1202 prevFormPage: function() {
1203
1204 var $button = $( this ),
1205 $fromPage = $button.closest( '.jet-form-builder-page' ),
1206 $toPage = $fromPage.prev();
1207
1208 JetFormBuilder.switchFormPage( $fromPage, $toPage );
1209 },
1210
1211 isFieldsValid: function( $fields ) {
1212 var isValid = true;
1213
1214 $fields.each( function( ind, field ) {
1215 if ( ! field.checkValidity() ) {
1216 isValid = false;
1217 } else {
1218 return isValid;
1219 }
1220 if ( ! field.classList.contains( 'jet-form-builder-file-upload__input' ) ) {
1221 field.reportValidity();
1222 return isValid;
1223 }
1224 const preset = field.closest( '.jet-form-builder-file-upload' ).querySelector( '.jet-form-builder-file-upload__value' );
1225
1226 isValid = !! preset?.value;
1227
1228 if ( ! isValid ) {
1229 field.reportValidity();
1230 return isValid;
1231 }
1232 } );
1233
1234 return isValid;
1235 },
1236
1237 switchFormPage: function( $fromPage, $toPage ) {
1238 const $form = $fromPage.closest( '.jet-form-builder' );
1239 const $conditional = $fromPage.closest( '.jet-form-builder__conditional' );
1240 let $progress = null;
1241
1242 if ( ! $conditional.length ) {
1243 $progress = $form.find( '.jet-form-builder-progress-pages--global' );
1244 }
1245
1246 $fromPage.addClass( 'jet-form-builder-page--hidden' );
1247 $toPage.removeClass( 'jet-form-builder-page--hidden' );
1248
1249 window.scrollTo( 0, $toPage.offset().top + ( +JetFormBuilderSettings.scrollOffset ) );
1250
1251 JetFormBuilder.initSingleFormPage( $toPage, false );
1252
1253 $( '.jet-form-builder-messages-wrap[data-form-id="' + $form.data( 'form-id' ) + '"]' ).html( '' );
1254 $( document ).trigger( 'jet-form-builder/switch-page', [ $fromPage, $toPage, $progress ] );
1255 },
1256
1257 getFieldValue: function( $field ) {
1258
1259 var val = 0;
1260
1261 if ( $field.length ) {
1262
1263 if ( 'INPUT' === $field[ 0 ].nodeName ) {
1264 if ( $field.length > 1 ) {
1265
1266 for ( var i = 0; i < $field.length; i++ ) {
1267 if ( $field[ i ].checked ) {
1268
1269 var itemVal = 0;
1270
1271 if ( undefined !== $field[ i ].dataset.calculate ) {
1272 itemVal = $field[ i ].dataset.calculate;
1273 } else {
1274 itemVal = $field[ i ].value;
1275 }
1276
1277 if ( 'checkbox' === $field[ i ].type ) {
1278 val += parseFloat( itemVal );
1279 } else {
1280 val = itemVal;
1281 }
1282
1283 }
1284 }
1285
1286 } else {
1287 if ( 'checkbox' === $field[ 0 ].type ) {
1288 if ( $field[ 0 ].checked ) {
1289 if ( undefined !== $field[ 0 ].dataset.calculate ) {
1290 val = $field[ 0 ].dataset.calculate;
1291 } else {
1292 val = $field[ 0 ].value;
1293 }
1294 }
1295 } else {
1296 const rawValue = $field.val();
1297
1298 val = Number.isNaN( Number( rawValue ) )
1299 ? rawValue
1300 : parseFloat( rawValue );
1301 }
1302 }
1303 }
1304
1305 if ( 'SELECT' === $field[ 0 ].nodeName ) {
1306
1307 var selectedOption = $field.find( 'option:selected' ),
1308 calcValue = selectedOption.data( 'calculate' );
1309
1310 if ( undefined !== calcValue ) {
1311 val = calcValue;
1312 } else {
1313 val = $field.find( 'option:selected' ).val();
1314 }
1315
1316 }
1317
1318 if ( 'DIV' === $field[ 0 ].nodeName ) {
1319
1320 if ( $field.hasClass( 'jet-form-builder-repeater' ) ) {
1321 var repeaterSettings = $field.data( 'settings' );
1322 if ( repeaterSettings && 'custom' === repeaterSettings.calcType ) {
1323 $field.find( '.jet-form-builder-repeater__row' ).each( function() {
1324 var $row = $( this ),
1325 rowVal = JetFormBuilder.calculateValue( $row );
1326
1327 $row.data( 'value', rowVal );
1328
1329 val += rowVal;
1330 } );
1331
1332 } else {
1333 val = $field.find( '.jet-form-builder-repeater__row' ).length;
1334 }
1335 }
1336
1337 }
1338
1339 }
1340
1341 if ( ! val ) {
1342 val = '0';
1343 }
1344
1345 val = JetFormBuilderMain.filters.applyFilters( 'forms/calculated-field-value', val, $field );
1346
1347 return val;
1348
1349 },
1350
1351 calculateValue: function( $scope ) {
1352
1353 var formula = String( $scope.data( 'formula' ) ),
1354 //listenTo = $( '[name^="' + $scope.data( 'listen_to' ) + '"]', $scope.closest( 'form' ) ),
1355 regexp = /%([a-zA-Z0-9-_]+)%/g,
1356 func = null,
1357 $form = $scope.closest( 'form' );
1358
1359 if ( typeof formula === 'undefined' || ! $form.length ) {
1360 return 0;
1361 }
1362
1363 const getGlobalObj = name => {
1364 return $form.find( '[name="' + name + '"], [name="' + name + '[]"]' )
1365 };
1366
1367 formula = JetFormBuilderMain.filters.applyFilters( 'forms/calculated-formula-before-value', formula, $scope );
1368
1369 formula = formula.replace( regexp, function( match1, match2 ) {
1370
1371 var object = null;
1372
1373 if ( $scope.data( 'repeater' ) ) {
1374 object = $scope;
1375 } else if ( $scope.hasClass( 'jet-form-builder__calculated-field--child' ) ) {
1376 object = $scope.closest( '.jet-form-builder-repeater__row' ).find( '[data-field-name="' + match2 + '"]' );
1377
1378 if ( ! object.length ) {
1379 object = getGlobalObj( match2 );
1380 }
1381
1382 } else if ( $scope.data( 'repeater-row' ) ) {
1383 object = $scope.find( '[data-field-name="' + match2 + '"]' );
1384 } else {
1385 object = getGlobalObj( match2 );
1386 }
1387
1388 return JetFormBuilder.getFieldValue( object );
1389
1390 } );
1391
1392 formula = JetFormBuilderMain.filters.applyFilters( 'forms/calculated-formula-after-value', formula, $scope );
1393
1394 func = new Function( 'return ' + formula );
1395
1396 return func();
1397
1398 },
1399
1400 convertCalcValue: function( value, sepDecimal, sepThousands ) {
1401 const parts = value.toString().split( '.' );
1402 parts[ 0 ] = parts[ 0 ].replace( /\B(?=(\d{3})+(?!\d))/g, sepThousands );
1403
1404 return parts.join( sepDecimal );
1405 },
1406
1407 setCalculatedValue: function( calculatedValue, calcField ) {
1408 const fieldPrecision = calcField.data( 'precision' );
1409 const number = calculatedValue.toFixed( fieldPrecision );
1410
1411 const visibleNumber = JetFormBuilder.convertCalcValue(
1412 number,
1413 calcField.data( 'sep-decimal' ) || '.',
1414 calcField.data( 'sep-thousands' ) || '',
1415 );
1416
1417 calcField.find( '.jet-form-builder__calculated-field-val' ).text( visibleNumber );
1418 calcField.find( '.jet-form-builder__calculated-field-input' ).val( number ).trigger( 'change.JetFormBuilderMain' );
1419 },
1420
1421 recalcFields: function( event ) {
1422
1423 var $this = $( this ),
1424 fieldName = $this.attr( 'name' ),
1425 calculated = null;
1426
1427 if ( $this.data( 'field-name' ) ) {
1428 fieldName = $this.data( 'field-name' );
1429 }
1430
1431 if ( ! fieldName ) {
1432 return;
1433 }
1434 fieldName = fieldName.replace( '[]', '' );
1435
1436 $.each( JetFormBuilder.calcFields, function( calcFieldName, field ) {
1437
1438 if ( 0 <= $.inArray( fieldName, field.listenTo ) ) {
1439 calculated = JetFormBuilder.calculateValue( $( field.el ) );
1440
1441 JetFormBuilder.setCalculatedValue( calculated, $( field.el ) )
1442 }
1443 } );
1444
1445 if ( 'jet-form-builder/repeater-changed' !== event.type ) {
1446 $.each( JetFormBuilder.repeaterCalcFields, function( calcFieldName, field ) {
1447 if ( 0 <= $.inArray( fieldName, field.listenTo ) ) {
1448 field.el.trigger( 'jet-form-builder/repeater-changed' );
1449 }
1450 } );
1451 }
1452
1453 $.each( JetFormBuilder.childrenCalcFields, function( calcFieldName, field ) {
1454
1455 if ( 0 <= $.inArray( fieldName, field.listenTo ) ) {
1456 field.parentEl.find( '.jet-form-builder-repeater__row' ).each( function() {
1457 const $row = $( this );
1458
1459 JetFormBuilder.calculateFieldsInRow( $row )
1460 } );
1461 }
1462 } );
1463
1464 },
1465
1466 initRequiredCheckboxGroup: function( $scope ) {
1467 var $group = $scope.find( '.jet-form-builder__fields-group' );
1468
1469 $group.each( function() {
1470 var $this = $( this ),
1471 $checkboxes = $( '.checkboxes-group-required', $this );
1472
1473 if ( $checkboxes.length ) {
1474 var isChecked = $checkboxes.is( ':checked' );
1475
1476 $checkboxes.prop( 'required', ! isChecked );
1477 }
1478 } );
1479 },
1480
1481 requiredCheckboxGroup: function( event ) {
1482 var $this = $( event.target ),
1483 $group = $this.closest( '.jet-form-builder__fields-group' ),
1484 $checkboxes = $( '.checkboxes-field', $group );
1485
1486 if ( $checkboxes.length < 2 ) {
1487 return;
1488 }
1489
1490 var isChecked = $checkboxes.is( ':checked' );
1491
1492 $checkboxes.prop( 'required', ! isChecked );
1493 },
1494
1495 initRangeFields: function( $scope ) {
1496 var $rangeFields = $scope.find( '.jet-form-builder__field.range-field' );
1497
1498 if ( ! $rangeFields.length ) {
1499 return;
1500 }
1501
1502 $rangeFields.each( function() {
1503 JetFormBuilder.updateRangeField( { target: $( this ), firstInit: true } );
1504 } );
1505 },
1506
1507 updateRangeField: function( event ) {
1508 var $target = $( event.target ),
1509 $wrap = $target.closest( '.jet-form-builder__field-wrap' ),
1510 $number = $wrap.find( '.jet-form-builder__field-value-number' ),
1511 max = $target.attr( 'max' ) || 100,
1512 val = $target.val();
1513
1514 if ( event.firstInit ) {
1515 $number.text( max );
1516 }
1517
1518 $number.text( val );
1519 },
1520 getRecalculateFields: function ( $form ) {
1521 $form.find(
1522 '.jet-form-builder__calculated-field, .jet-form-builder__calculated-field--child'
1523 ).each( function() {
1524
1525 let $childCalculatedField = $( this ),
1526 val = JetFormBuilder.calculateValue( $childCalculatedField )
1527
1528 if ( ! val ) {
1529 val = 0;
1530 }
1531
1532 JetFormBuilder.setCalculatedValue( val, $childCalculatedField );
1533 } );
1534
1535 return true;
1536 },
1537
1538 reloadSubmitForm: function( event ) {
1539 event.preventDefault();
1540 const $target = $( event.target );
1541 const $maskedFields = $target.find( '.jet-form-builder__masked-field' );
1542
1543 if ( event.target?.checkValidity && event.target?.reportValidity && ! event.target.checkValidity() ) {
1544 event.target.reportValidity();
1545
1546 return;
1547 } else if ( JetFormBuilder.initSingleFormPage( $target, false ) ) {
1548 return;
1549 }
1550
1551 if ( $maskedFields && $maskedFields.length ) {
1552 $maskedFields.each( function() {
1553 const $maskedField = $( this );
1554
1555 // Remove mask if empty value
1556 if ( ! $maskedField.val() && $maskedField.inputmask ) {
1557 $maskedField.inputmask( 'remove' );
1558 }
1559 } );
1560 }
1561
1562 $target.addClass( 'is-loading' );
1563 $target.find( '.jet-form-builder__submit' ).attr( 'disabled', true );
1564
1565 Promise.all(
1566 applyFilters(
1567 'jet.fb.submit.reload.promises',
1568 [
1569 JetFormBuilder.getRecalculateFields( $target )
1570 ],
1571 event
1572 )
1573 ).then( () => event.target.submit() ).catch( () => {
1574 $target.removeClass( 'is-loading' );
1575 $target.find( '.jet-form-builder__submit' ).attr( 'disabled', false );
1576
1577 doAction( 'jet.fb.on.prevented.submit.reload', event );
1578 } );
1579 },
1580
1581 ajaxSubmitForm: function( event ) {
1582 event.preventDefault();
1583
1584 var $this = $( this ),
1585 $form = $this.closest( '.jet-form-builder' ),
1586 formID = $form.data( 'form-id' ),
1587 data = {};
1588
1589 if ( $form[ 0 ]?.checkValidity && $form[ 0 ]?.reportValidity && ! $form[ 0 ].checkValidity() ) {
1590 $form[ 0 ].reportValidity();
1591
1592 return;
1593 } else if ( JetFormBuilder.initSingleFormPage( $form, false ) ) {
1594 return;
1595 }
1596
1597 if ( window.tinyMCE ) {
1598 window.tinyMCE.triggerSave();
1599 }
1600
1601 JetFormBuilder.clearFieldErrors( formID );
1602
1603 const onSuccess = function( response ) {
1604
1605 $form.removeClass( 'is-loading' );
1606 $this.attr( 'disabled', false );
1607
1608 switch ( response.status ) {
1609
1610 case 'validation_failed':
1611
1612 Object.entries( response.fields ).forEach( function( [ fieldName, fieldData ] ) {
1613 var $field = JetFormBuilder.findFieldByName( $form, fieldName );
1614
1615 const afterMessage = `<div class="error-message">${ fieldData.message }</div>`;
1616
1617 $field.addClass( 'field-has-error' );
1618
1619 if ( $field.hasClass( 'checkradio-field' ) ) {
1620 $field.closest( '.jet-form-builder__field-wrap' ).after( afterMessage );
1621 } else {
1622 $field.after( afterMessage );
1623 }
1624
1625 JetFormBuilder.currentFieldWithError = {
1626 length: 0,
1627 };
1628 } );
1629
1630 break;
1631
1632 case 'success':
1633 $( document ).trigger( 'jet-form-builder/ajax/on-success', [ response, $form, data ] );
1634 break;
1635 }
1636
1637 if ( response.redirect ) {
1638 window.location = response.redirect;
1639 } else if ( response.reload ) {
1640 window.location.reload();
1641 }
1642
1643 $( '.jet-form-builder-messages-wrap[data-form-id="' + formID + '"]' ).html( response.message );
1644
1645 };
1646
1647 const onError = function ( jqXHR, textStatus, errorThrown ) {
1648 console.error( jqXHR.responseText, errorThrown );
1649
1650 removeLoading();
1651 }
1652
1653 const removeLoading = () => {
1654 $form.removeClass( 'is-loading' );
1655 $this.attr( 'disabled', false );
1656 };
1657
1658 const runAjaxForm = callbacks => {
1659 //data.values = $form.serializeArray();
1660 //data._jet_engine_booking_form_id = formID;
1661 const formData = new FormData( $form[ 0 ] );
1662 formData.append( '_jet_engine_booking_form_id', formID );
1663
1664 $.ajax( {
1665 url: JetFormBuilderSettings.ajaxurl,
1666 type: 'POST',
1667 dataType: 'json',
1668 data: formData,
1669 cache : false,
1670 contentType: false,
1671 processData: false,
1672 } ).done( response => {
1673 onSuccess( response );
1674 callbacks.forEach( cb => {
1675 if ( 'function' === typeof cb ) {
1676 cb.call( $form, response )
1677 }
1678 } );
1679
1680 } ).fail( onError );
1681 };
1682
1683 $form.addClass( 'is-loading' );
1684 $this.attr( 'disabled', true );
1685
1686 Promise.all(
1687 applyFilters(
1688 'jet.fb.submit.ajax.promises',
1689 [
1690 JetFormBuilder.getRecalculateFields( $form )
1691 ],
1692 $form,
1693 $this,
1694 data
1695 )
1696 ).then( runAjaxForm ).catch( () => {
1697 removeLoading();
1698 doAction( 'jet.fb.on.prevented.submit.ajax', $this, $form, data );
1699 } );
1700 },
1701
1702 clearFieldErrors: function( formID ) {
1703 var $this = $( this );
1704
1705 $this.closest( '.jet-form-builder-col' ).find( '.jet-form-builder__field-error' ).remove();
1706
1707 $( '.jet-form-builder__field.field-has-error' ).each( ( index, elem ) => {
1708 $( elem ).removeClass( 'field-has-error' );
1709 $( elem ).siblings( '.error-message' ).remove();
1710 } );
1711
1712 $( '.jet-form-builder-messages-wrap[data-form-id="' + formID + '"]' ).html( '' );
1713
1714 },
1715
1716 findFieldByName: function( form, fieldName ) {
1717 const callbackFinders = [
1718 'findInputDefault',
1719 'findWysiwyg',
1720 ];
1721
1722 callbackFinders.forEach( function( callback ) {
1723 if ( ! JetFormBuilder.currentFieldWithError || ! JetFormBuilder.currentFieldWithError.length ) {
1724 JetFormBuilder.currentFieldWithError = JetFormBuilder[ callback ]( form, fieldName );
1725 }
1726 } );
1727
1728 return JetFormBuilder.currentFieldWithError;
1729 },
1730
1731 findInputDefault: function( form, fieldName ) {
1732 return form.find( `.jet-form-builder-row [data-field-name="${ fieldName }"]:last` );
1733 },
1734
1735 findWysiwyg: function( form, fieldName ) {
1736 let field;
1737
1738 form.find( '.jet-form-builder__field[data-editor]' ).each( function( index, editor ) {
1739
1740 if ( fieldName === $( editor ).data( 'editor' ).textarea_name ) {
1741 field = $( editor );
1742 }
1743 } );
1744
1745 return field;
1746 },
1747
1748 addTriggersWysiwyg: function( field, editorId ) {
1749 const callable = function( e ) {
1750 field.trigger( 'change.JetFormBuilderMain', [ this ] );
1751 };
1752
1753 const editor = tinymce.get( editorId );
1754
1755 field.trigger( 'init.JetFormBuilderMain', [ editor ] );
1756
1757 editor
1758 .on( 'input', callable )
1759 .on( 'change', callable );
1760 },
1761 wysiwygInit: function( closure, replace = false ) {
1762 const self = $( closure ),
1763 editorID = self.attr( 'id' ),
1764 field = self.closest( '.jet-form-builder__field' );
1765
1766 if ( replace && window.tinymce && window.tinymce.get( editorID ) ) {
1767 window.tinymce.get( editorID ).remove();
1768 }
1769
1770 window.wp.editor.initialize(
1771 editorID,
1772 field.data( 'editor' ),
1773 );
1774
1775 return { editorID, field };
1776 },
1777 wysiwygInitWithTriggers: function( closure, replace = false ) {
1778 const { editorID, field } = JetFormBuilder.wysiwygInit( closure, replace );
1779
1780 JetFormBuilder.addTriggersWysiwyg( field, editorID );
1781 },
1782
1783 };
1784
1785 window.JetFormBuilderDev = JetFormBuilderDev;
1786 window.JetFormBuilder = JetFormBuilder;
1787
1788 $( JetFormBuilder.initCommon );
1789 $( window ).on( 'elementor/frontend/init', JetFormBuilder.initElementor );
1790
1791 JetFormBuilder.addHandlersInit();
1792 } )( jQuery );
1793