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