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