PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 4.11.02
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v4.11.02
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
← All changes | js/formidable_admin.js +1071 -4055 6.3.24.11.02 View file →
@@ -266,9 +266,9 @@
266 266 plugin: 'formidable_pro',
267 267 nonce: frmGlobal.nonce
268 268 },
269 269 success: function( msg ) {
270 - el.reset.textContent = msg.message;
270 + el.reset.innerHTML = msg.message;
271 271 if ( el.reset.getAttribute( 'data-refresh' ) === '1' ) {
272 272 window.location.reload();
273 273 }
274 274 }
@@ -314,21 +314,14 @@
314 314
315 315 function frmAdminBuildJS() {
316 316 //'use strict';
317 317
318 - /*global jQuery:false, frm_admin_js, frmGlobal, ajaxurl, fromDom */
318 + /*global jQuery:false, frm_admin_js, frmGlobal, ajaxurl */
319 319
320 - const { tag, div, span, a, svg, img } = frmDom;
321 - const { onClickPreventDefault } = frmDom.util;
322 - const { doJsonFetch, doJsonPost } = frmDom.ajax;
323 - const icons = {
324 - save: svg({ href: '#frm_save_icon' }),
325 - drag: svg({ href: '#frm_drag_icon', classList: [ 'frm_drag_icon', 'frm-drag' ] })
326 - };
327 -
328 - let $newFields = jQuery( document.getElementById( 'frm-show-fields' ) ),
320 + var $newFields = jQuery( document.getElementById( 'frm-show-fields' ) ),
329 321 builderForm = document.getElementById( 'new_fields' ),
330 322 thisForm = document.getElementById( 'form_id' ),
323 + cancelSort = false,
331 324 copyHelper = false,
332 325 fieldsUpdated = 0,
333 326 thisFormId = 0,
334 327 autoId = 0,
@@ -334,11 +327,8 @@
334 327 autoId = 0,
335 328 optionMap = {},
336 329 lastNewActionIdReturned = 0;
337 330
338 - const { __ } = wp.i18n;
339 - let debouncedSyncAfterDragAndDrop, postBodyContent, $postBodyContent;
340 -
341 331 if ( thisForm !== null ) {
342 332 thisFormId = thisForm.value;
343 333 }
344 334
@@ -386,9 +376,9 @@
386 376 }
387 377 }
388 378
389 379 function confirmModal( link ) {
390 - var verify, $confirmMessage, i, dataAtts, btnClass,
380 + var caution, verify, $confirmMessage, frmCaution, i, dataAtts,
391 381 $info = initModal( '#frm_confirm_modal', '400px' ),
392 382 continueButton = document.getElementById( 'frm-confirmed-click' );
393 383
394 384 if ( $info === false ) {
@@ -394,18 +384,22 @@
394 384 if ( $info === false ) {
395 385 return false;
396 386 }
397 387
388 + caution = link.getAttribute( 'data-frmcaution' );
398 389 verify = link.getAttribute( 'data-frmverify' );
399 - btnClass = verify ? link.getAttribute( 'data-frmverify-btn' ) : '';
400 390 $confirmMessage = jQuery( '.frm-confirm-msg' );
401 391 $confirmMessage.empty();
402 392
393 + if ( caution ) {
394 + frmCaution = document.createElement( 'span' );
395 + frmCaution.classList.add( 'frm-caution' );
396 + frmCaution.appendChild( document.createTextNode( caution ) );
397 + $confirmMessage.append( frmCaution );
398 + }
399 +
403 400 if ( verify ) {
404 401 $confirmMessage.append( document.createTextNode( verify ) );
405 - if ( btnClass ) {
406 - continueButton.classList.add( btnClass );
407 - }
408 402 }
409 403
410 404 removeAtts = continueButton.dataset;
411 405 for ( i in dataAtts ) {
@@ -452,40 +446,25 @@
452 446 }
453 447
454 448 if ( text !== null && text !== '' ) {
455 449 this.setAttribute( 'data-toggletext', this.innerHTML );
456 - this.textContent = text;
450 + this.innerHTML = text;
457 451 }
458 452
459 453 return false;
460 454 }
461 455
462 - /**
463 - * Toggle a class on target elements when an anchor is clicked, or when a radio or checkbox has been selected.
464 - *
465 - * @param {Event} e Event with either the change or click type.
466 - * @returns {false}
467 - */
468 456 function hideShowItem( e ) {
469 457 /*jshint validthis:true */
470 - let hide = this.getAttribute( 'data-frmhide' );
471 - let show = this.getAttribute( 'data-frmshow' );
458 + var hide = this.getAttribute( 'data-frmhide' ),
459 + show = this.getAttribute( 'data-frmshow' ),
460 + toggleClass = this.getAttribute( 'data-toggleclass' );
472 461
473 - // Flip unchecked checkboxes so an off value undoes the on value.
474 - if ( isUncheckedCheckbox( this ) ) {
475 - if ( hide !== null ) {
476 - show = hide;
477 - hide = null;
478 - } else if ( show !== null ) {
479 - hide = show;
480 - show = null;
481 - }
462 + e.preventDefault();
463 + if ( toggleClass === null ) {
464 + toggleClass = 'frm_hidden';
482 465 }
483 466
484 - e.preventDefault();
485 -
486 - const toggleClass = this.getAttribute( 'data-toggleclass' ) || 'frm_hidden';
487 -
488 467 if ( hide !== null ) {
489 468 jQuery( hide ).addClass( toggleClass );
490 469 }
491 470
@@ -503,12 +482,8 @@
503 482
504 483 return false;
505 484 }
506 485
507 - function isUncheckedCheckbox( element ) {
508 - return 'INPUT' === element.nodeName && 'checkbox' === element.type && ! element.checked;
509 - }
510 -
511 486 function setupMenuOffset() {
512 487 window.onscroll = document.documentElement.onscroll = setMenuOffset;
513 488 setMenuOffset();
514 489 }
@@ -567,9 +542,8 @@
567 542 wrapClass.on( 'click', '.frm_remove_tag, .frm_remove_form_action', removeThisTag );
568 543 wrapClass.on( 'click', 'a[data-frmverify]', confirmClick );
569 544 wrapClass.on( 'click', 'a[data-frmtoggle]', toggleItem );
570 545 wrapClass.on( 'click', 'a[data-frmhide], a[data-frmshow]', hideShowItem );
571 - wrapClass.on( 'change', 'input[data-frmhide], input[data-frmshow]', hideShowItem );
572 546 wrapClass.on( 'click', '.widget-top,a.widget-action', clickWidget );
573 547
574 548 wrapClass.on( 'mouseenter.frm', '.frm_bstooltip, .frm_help', function() {
575 549 jQuery( this ).off( 'mouseenter.frm' );
@@ -612,39 +586,30 @@
612 586 }
613 587 });
614 588 }
615 589
616 - function deleteTooltips() {
617 - document.querySelectorAll( '.tooltip' ).forEach(
618 - function( tooltip ) {
619 - tooltip.remove();
620 - }
621 - );
622 - }
623 -
624 590 function removeThisTag() {
625 591 /*jshint validthis:true */
626 - let show, hide, removeMore;
592 + var show, hide, removeMore,
593 + id = '',
594 + deleteButton = jQuery( this ),
595 + continueRemove = confirmLinkClick( this );
627 596
628 - if ( parseInt( this.getAttribute( 'data-skip-frm-js' ) ) || confirmLinkClick( this ) === false ) {
597 + if ( continueRemove === false ) {
629 598 return;
599 + } else {
600 + id = deleteButton.attr( 'data-removeid' );
601 + show = deleteButton.attr( 'data-showlast' );
602 + removeMore = deleteButton.attr( 'data-removemore' );
603 + if ( typeof show === 'undefined' ) {
604 + show = '';
605 + }
606 + hide = deleteButton.attr( 'data-hidelast' );
607 + if ( typeof hide === 'undefined' ) {
608 + hide = '';
609 + }
630 610 }
631 611
632 - const deleteButton = jQuery( this );
633 - const id = deleteButton.attr( 'data-removeid' );
634 -
635 - show = deleteButton.attr( 'data-showlast' );
636 - if ( typeof show === 'undefined' ) {
637 - show = '';
638 - }
639 -
640 - hide = deleteButton.attr( 'data-hidelast' );
641 - if ( typeof hide === 'undefined' ) {
642 - hide = '';
643 - }
644 -
645 - removeMore = deleteButton.attr( 'data-removemore' );
646 -
647 612 if ( show !== '' ) {
648 613 if ( deleteButton.closest( '.frm_add_remove' ).find( '.frm_remove_tag:visible' ).length > 1 ) {
649 614 show = '';
650 615 hide = '';
@@ -660,9 +625,9 @@
660 625 show += '#' + jQuery( '#frm_postmeta_rows .frm_postmeta_row:not(#' + id + ')' ).last().attr( 'id' ) + ' .frm_toggle_cf_opts';
661 626 }
662 627 }
663 628
664 - const $fadeEle = jQuery( document.getElementById( id ) );
629 + var $fadeEle = jQuery( document.getElementById( id ) );
665 630 $fadeEle.fadeOut( 400, function() {
666 631 $fadeEle.remove();
667 632 fieldUpdated();
668 633
@@ -673,11 +638,12 @@
673 638 if ( show !== '' ) {
674 639 jQuery( show + ' a,' + show ).removeClass( 'frm_hidden' ).fadeIn( 'slow' );
675 640 }
676 641
677 - if ( this.closest( '.frm_form_action_settings' ) ) {
678 - const type = this.closest( '.frm_form_action_settings' ).querySelector( '.frm_action_name' ).value;
679 - afterActionRemoved( type );
642 + var action = jQuery( this ).closest( '.frm_form_action_settings' );
643 + if ( typeof action !== 'undefined' ) {
644 + var type = jQuery( this ).closest( '.frm_form_action_settings' ).find( '.frm_action_name' ).val();
645 + checkActiveAction( type );
680 646 }
681 647 });
682 648
683 649 if ( typeof removeMore !== 'undefined' ) {
@@ -693,18 +659,11 @@
693 659
694 660 return false;
695 661 }
696 662
697 - function afterActionRemoved( type ) {
698 - checkActiveAction( type );
699 -
700 - const hookName = 'frm_after_action_removed';
701 - const hookArgs = { type };
702 - wp.hooks.doAction( hookName, hookArgs );
703 - }
704 -
705 663 function clickWidget( event, b ) {
706 664 /*jshint validthis:true */
665 + var target = event.target;
707 666 if ( typeof b === 'undefined' ) {
708 667 b = this;
709 668 }
710 669
@@ -709,13 +668,11 @@
709 668 }
710 669
711 670 popCalcFields( b, false );
712 671
713 - const cont = jQuery( b ).closest( '.frm_form_action_settings' );
714 - const target = event.target;
715 -
672 + var cont = jQuery( b ).closest( '.frm_form_action_settings' );
716 673 if ( cont.length && typeof target !== 'undefined' ) {
717 - const className = target.parentElement.className;
674 + var className = target.parentElement.className;
718 675 if ( 'string' === typeof className ) {
719 676 if ( className.indexOf( 'frm_email_icons' ) > -1 || className.indexOf( 'frm_toggle' ) > -1 ) {
720 677 // clicking on delete icon shouldn't open it
721 678 event.stopPropagation();
@@ -723,13 +680,13 @@
723 680 }
724 681 }
725 682 }
726 683
727 - let inside = cont.children( '.widget-inside' );
684 + var inside = cont.children( '.widget-inside' );
728 685
729 686 if ( cont.length && inside.find( 'p, div, table' ).length < 1 ) {
730 - const actionId = cont.find( 'input[name$="[ID]"]' ).val();
731 - const actionType = cont.find( 'input[name$="[post_excerpt]"]' ).val();
687 + var actionId = cont.find( 'input[name$="[ID]"]' ).val();
688 + var actionType = cont.find( 'input[name$="[post_excerpt]"]' ).val();
732 689 if ( actionType ) {
733 690 inside.html( '<span class="frm-wait frm_spinner"></span>' );
734 691 cont.find( '.spinner' ).fadeIn( 'slow' );
735 692 jQuery.ajax({
@@ -744,19 +701,10 @@
744 701 success: function( html ) {
745 702 inside.html( html );
746 703 initiateMultiselect();
747 704 showInputIcon( '#' + cont.attr( 'id' ) );
748 - frmDom.autocomplete.initAutocomplete( 'page', inside );
705 + initAutocomplete( 'page', inside );
749 706 jQuery( b ).trigger( 'frm-action-loaded' );
750 -
751 - /**
752 - * Fires after filling form action content when opening.
753 - *
754 - * @since 5.5.4
755 - *
756 - * @param {Object} insideElement JQuery object of form action inside element.
757 - */
758 - wp.hooks.doAction( 'frm_filled_form_action', inside );
759 707 }
760 708 });
761 709 }
762 710 }
@@ -840,696 +788,114 @@
840 788 jQuery( '.frm_settings_form' ).attr( 'action', '?page=formidable-settings&t=' + t.replace( '#', '' ) );
841 789 }
842 790 }
843 791
844 - function setupSortable( sortableSelector ) {
845 - document.querySelectorAll( sortableSelector ).forEach(
846 - list => {
847 - makeDroppable( list );
848 - Array.from( list.children ).forEach( child => makeDraggable( child, '.frm-move' ) );
792 + /* Form Builder */
793 + function setupSortable( sort ) {
794 + var startSort = false,
795 + container = jQuery( '#post-body-content' );
849 796
850 - const $sectionTitle = jQuery( list ).children( '[data-type="divider"]' ).children( '.divider_section_only' );
851 - if ( $sectionTitle.length ) {
852 - makeDroppable( $sectionTitle );
853 - }
854 - }
855 - );
856 - setupFieldOptionSorting( jQuery( '#frm_builder_page' ) );
857 - }
797 + var opts = {
798 + connectWith: 'ul.frm_sorting',
799 + items: '> li.frm_field_box',
800 + placeholder: 'sortable-placeholder',
801 + axis: 'y',
802 + cancel: '.widget,.frm_field_opts_list,input,textarea,select,.edit_field_type_end_divider,.frm_sortable_field_opts,.frm_noallow',
803 + accepts: 'field_type_list',
804 + forcePlaceholderSize: false,
805 + tolerance: 'pointer',
806 + handle: '.frm-move',
807 + over: function() {
808 + this.classList.add( 'drop-me' );
809 + },
810 + out: function() {
811 + this.classList.remove( 'drop-me' );
812 + },
813 + receive: function( event, ui ) {
814 + // Receive event occurs when an item in one sortable list is dragged into another sortable list
858 815
859 - function makeDroppable( list ) {
860 - jQuery( list ).droppable({
861 - accept: '.frmbutton, li.frm_field_box',
862 - deactivate: handleFieldDrop,
863 - over: onDragOverDroppable,
864 - out: onDraggableLeavesDroppable,
865 - tolerance: 'pointer'
866 - });
867 - }
868 -
869 - function onDragOverDroppable( event, ui ) {
870 - const droppable = getDroppableForOnDragOver( event.target );
871 - const draggable = ui.draggable[0];
872 -
873 - if ( ! allowDrop( draggable, droppable ) ) {
874 - droppable.classList.remove( 'frm-over-droppable' );
875 - jQuery( droppable ).parents( 'ul.frm_sorting' ).addClass( 'frm-over-droppable' );
876 - return;
877 - }
878 -
879 - document.querySelectorAll( '.frm-over-droppable' ).forEach( droppable => droppable.classList.remove( 'frm-over-droppable' ) );
880 - droppable.classList.add( 'frm-over-droppable' );
881 - jQuery( droppable ).parents( 'ul.frm_sorting' ).addClass( 'frm-over-droppable' );
882 - }
883 -
884 - /**
885 - * Maybe change the droppable.
886 - * Section titles are made droppable, but are not a list, so we need to change the droppable to the section's list instead.
887 - *
888 - * @param {Element} droppable
889 - * @returns {Element}
890 - */
891 - function getDroppableForOnDragOver( droppable ) {
892 - if ( droppable.classList.contains( 'divider_section_only' ) ) {
893 - droppable = jQuery( droppable ).nextAll( '.start_divider.frm_sorting' ).get( 0 );
894 - }
895 - return droppable;
896 - }
897 -
898 - function onDraggableLeavesDroppable( event ) {
899 - const droppable = event.target;
900 - droppable.classList.remove( 'frm-over-droppable' );
901 - }
902 -
903 - function makeDraggable( draggable, handle ) {
904 - const settings = {
905 - helper: getDraggableHelper,
906 - revert: 'invalid',
907 - delay: 10,
908 - start: handleDragStart,
909 - stop: handleDragStop,
910 - drag: handleDrag,
911 - cursor: 'grabbing',
912 - refreshPositions: true,
913 - cursorAt: {
914 - top: 0,
915 - left: 90 // The width of draggable button is 180. 90 should center the draggable on the cursor.
916 - }
917 - };
918 - if ( 'string' === typeof handle ) {
919 - settings.handle = handle;
920 - }
921 - jQuery( draggable ).draggable( settings );
922 - }
923 -
924 - function getDraggableHelper( event ) {
925 - const draggable = event.delegateTarget;
926 -
927 - if ( isFieldGroup( draggable ) ) {
928 - const newTextFieldClone = document.getElementById( 'frm-insert-fields' ).querySelector( '.frm_ttext' ).cloneNode( true );
929 - newTextFieldClone.querySelector( 'use' ).setAttributeNS( 'http://www.w3.org/1999/xlink', 'href', '#frm_field_group_layout_icon' );
930 - newTextFieldClone.querySelector( 'span' ).textContent = __( 'Field Group' );
931 - newTextFieldClone.classList.add( 'frm_field_box' );
932 - newTextFieldClone.classList.add( 'ui-sortable-helper' );
933 - return newTextFieldClone;
934 - }
935 -
936 - let copyTarget;
937 - const isNewField = draggable.classList.contains( 'frmbutton' );
938 - if ( isNewField ) {
939 - copyTarget = draggable.cloneNode( true );
940 - copyTarget.classList.add( 'ui-sortable-helper' );
941 - draggable.classList.add( 'frm-new-field' );
942 - return copyTarget;
943 - }
944 -
945 - if ( draggable.hasAttribute( 'data-ftype' ) ) {
946 - const fieldType = draggable.getAttribute( 'data-ftype' );
947 - copyTarget = document.getElementById( 'frm-insert-fields' ).querySelector( '.frm_t' + fieldType );
948 - copyTarget = copyTarget.cloneNode( true );
949 - copyTarget.classList.add( 'form-field' );
950 -
951 - copyTarget.classList.add( 'ui-sortable-helper' );
952 -
953 - if ( copyTarget ) {
954 - return copyTarget.cloneNode( true );
955 - }
956 - }
957 -
958 - return div({ className: 'frmbutton' });
959 - }
960 -
961 - function handleDragStart( event, ui ) {
962 - const container = postBodyContent;
963 - container.classList.add( 'frm-dragging-field' );
964 -
965 - document.body.classList.add( 'frm-dragging' );
966 - ui.helper.addClass( 'frm-sortable-helper' );
967 - ui.helper.initialOffset = container.scrollTop;
968 -
969 - event.target.classList.add( 'frm-drag-fade' );
970 -
971 - unselectFieldGroups();
972 - deleteEmptyDividerWrappers();
973 - maybeRemoveGroupHoverTarget();
974 - closeOpenFieldDropdowns();
975 - deleteTooltips();
976 - }
977 -
978 - function handleDragStop() {
979 - const container = postBodyContent;
980 - container.classList.remove( 'frm-dragging-field' );
981 - document.body.classList.remove( 'frm-dragging' );
982 -
983 - const fade = document.querySelector( '.frm-drag-fade' );
984 - if ( fade ) {
985 - fade.classList.remove( 'frm-drag-fade' );
986 - }
987 - }
988 -
989 - function handleDrag( event, ui ) {
990 - maybeScrollBuilder( event );
991 - const draggable = event.target;
992 - const droppable = getDroppableTarget();
993 -
994 - let placeholder = document.getElementById( 'frm_drag_placeholder' );
995 -
996 - if ( ! allowDrop( draggable, droppable ) ) {
997 - if ( placeholder ) {
998 - placeholder.remove();
999 - }
1000 - return;
1001 - }
1002 -
1003 - if ( ! placeholder ) {
1004 - placeholder = tag( 'li', {
1005 - id: 'frm_drag_placeholder',
1006 - className: 'sortable-placeholder'
1007 - });
1008 - }
1009 - const frmSortableHelper = ui.helper.get( 0 );
1010 - if ( frmSortableHelper.classList.contains( 'form-field' ) || frmSortableHelper.classList.contains( 'frm_field_box' ) ) {
1011 - // Sync the y position of the draggable so it still follows the cursor after scrolling up and down the field list.
1012 - frmSortableHelper.style.transform = 'translateY(' + getDragOffset( ui.helper ) + 'px)';
1013 - }
1014 -
1015 - if ( 'frm-show-fields' === droppable.id || droppable.classList.contains( 'start_divider' ) ) {
1016 - placeholder.style.left = 0;
1017 - handleDragOverYAxis({ droppable, y: event.clientY, placeholder });
1018 - return;
1019 - }
1020 -
1021 - placeholder.style.top = '';
1022 - handleDragOverFieldGroup({ droppable, x: event.clientX, placeholder });
1023 - }
1024 -
1025 - function maybeScrollBuilder( event ) {
1026 - $postBodyContent.scrollTop(
1027 - ( _, v ) => {
1028 - const moved = event.clientY;
1029 - const h = postBodyContent.offsetHeight;
1030 - const relativePos = event.clientY - postBodyContent.offsetTop;
1031 - const y = relativePos - h / 2;
1032 -
1033 - if ( relativePos > ( h - 50 ) && moved > 5 ) {
1034 - // Scrolling down.
1035 - return v + y * 0.1;
816 + if ( cancelSort ) {
817 + ui.item.addClass( 'frm_cancel_sort' );
818 + return;
1036 819 }
1037 820
1038 - if ( relativePos < 70 && moved < 130 ) {
1039 - // Scrolling up.
1040 - return v - Math.abs( y * 0.1 );
1041 - }
1042 -
1043 - return v;
1044 - }
1045 - );
1046 - }
1047 -
1048 - function getDragOffset( $helper ) {
1049 - return postBodyContent.scrollTop - $helper.initialOffset;
1050 - }
1051 -
1052 - function getDroppableTarget() {
1053 - let droppable = document.getElementById( 'frm-show-fields' );
1054 - while ( droppable.querySelector( '.frm-over-droppable' ) ) {
1055 - droppable = droppable.querySelector( '.frm-over-droppable' );
1056 - }
1057 - if ( 'frm-show-fields' === droppable.id && ! droppable.classList.contains( 'frm-over-droppable' ) ) {
1058 - droppable = false;
1059 - }
1060 - return droppable;
1061 - }
1062 -
1063 - function handleFieldDrop( _, ui ) {
1064 - const draggable = ui.draggable[0];
1065 - const placeholder = document.getElementById( 'frm_drag_placeholder' );
1066 -
1067 - if ( ! placeholder ) {
1068 - ui.helper.remove();
1069 - debouncedSyncAfterDragAndDrop();
1070 - return;
1071 - }
1072 -
1073 - maybeOpenCollapsedPage( placeholder );
1074 -
1075 - const $previousFieldContainer = ui.helper.parent();
1076 - const previousSection = ui.helper.get( 0 ).closest( 'ul.start_divider' );
1077 - const newSection = placeholder.closest( 'ul.frm_sorting' );
1078 -
1079 - if ( draggable.classList.contains( 'frm-new-field' ) ) {
1080 - insertNewFieldByDragging( draggable.id );
1081 - } else {
1082 - moveFieldThatAlreadyExists( draggable, placeholder );
1083 - }
1084 -
1085 - const previousSectionId = previousSection ? parseInt( previousSection.closest( '.edit_field_type_divider' ).getAttribute( 'data-fid' ) ) : 0;
1086 - const newSectionId = newSection.classList.contains( 'start_divider' ) ? parseInt( newSection.closest( '.edit_field_type_divider' ).getAttribute( 'data-fid' ) ) : 0;
1087 -
1088 - placeholder.remove();
1089 - ui.helper.remove();
1090 -
1091 - const $previousContainerFields = $previousFieldContainer.length ? getFieldsInRow( $previousFieldContainer ) : [];
1092 - maybeUpdatePreviousFieldContainerAfterDrop( $previousFieldContainer, $previousContainerFields );
1093 - maybeUpdateDraggableClassAfterDrop( draggable, $previousContainerFields );
1094 -
1095 - if ( previousSectionId !== newSectionId ) {
1096 - updateFieldAfterMovingBetweenSections( jQuery( draggable ), previousSection );
1097 - }
1098 -
1099 - debouncedSyncAfterDragAndDrop();
1100 - }
1101 -
1102 - /**
1103 - * If a page if collapsed, expand it before dragging since only the page break will move.
1104 - *
1105 - * @param {Element} placeholder
1106 - * @returns {void}
1107 - */
1108 - function maybeOpenCollapsedPage( placeholder ) {
1109 - if ( ! placeholder.previousElementSibling || ! placeholder.previousElementSibling.classList.contains( 'frm-is-collapsed' ) ) {
1110 - return;
1111 - }
1112 -
1113 - const $pageBreakField = jQuery( placeholder ).prevUntil( '[data-type="break"]' );
1114 - if ( ! $pageBreakField.length ) {
1115 - return;
1116 - }
1117 -
1118 - const collapseButton = $pageBreakField.find( '.frm-collapse-page' ).get( 0 );
1119 - if ( collapseButton ) {
1120 - collapseButton.click();
1121 - }
1122 - }
1123 -
1124 - function maybeUpdatePreviousFieldContainerAfterDrop( $previousFieldContainer, $previousContainerFields ) {
1125 - if ( ! $previousFieldContainer.length ) {
1126 - return;
1127 - }
1128 -
1129 - if ( $previousContainerFields.length ) {
1130 - syncLayoutClasses( $previousContainerFields.first() );
1131 - } else {
1132 - maybeDeleteAnEmptyFieldGroup( $previousFieldContainer.get( 0 ) );
1133 - }
1134 - }
1135 -
1136 - function maybeUpdateDraggableClassAfterDrop( draggable, $previousContainerFields ) {
1137 - if ( 0 !== $previousContainerFields.length || 1 !== getFieldsInRow( jQuery( draggable.parentNode ) ).length ) {
1138 - syncLayoutClasses( jQuery( draggable ) );
1139 - }
1140 - }
1141 -
1142 - /**
1143 - * Remove an empty field group, but don't remove an empty section.
1144 - *
1145 - * @param {Element} previousFieldContainer
1146 - * @returns {void}
1147 - */
1148 - function maybeDeleteAnEmptyFieldGroup( previousFieldContainer ) {
1149 - const closestFieldBox = previousFieldContainer.closest( 'li.frm_field_box' );
1150 - if ( closestFieldBox && ! closestFieldBox.classList.contains( 'edit_field_type_divider' ) ) {
1151 - closestFieldBox.remove();
1152 - }
1153 - }
1154 -
1155 - function handleDragOverYAxis({ droppable, y, placeholder }) {
1156 - const $list = jQuery( droppable );
1157 -
1158 - let top;
1159 -
1160 - $children = $list.children().not( '.edit_field_type_end_divider' );
1161 - if ( 0 === $children.length ) {
1162 - $list.prepend( placeholder );
1163 - top = 0;
1164 - } else {
1165 - const insertAtIndex = determineIndexBasedOffOfMousePositionInList( $list, y );
1166 -
1167 - if ( insertAtIndex === $children.length ) {
1168 - const $lastChild = jQuery( $children.get( insertAtIndex - 1 ) );
1169 - top = $lastChild.offset().top + $lastChild.outerHeight();
1170 - $list.append( placeholder );
1171 -
1172 - // Make sure nothing gets inserted after the end divider.
1173 - const $endDivider = $list.children( '.edit_field_type_end_divider' );
1174 - if ( $endDivider.length ) {
1175 - $list.append( $endDivider );
1176 - }
1177 - } else {
1178 - top = jQuery( $children.get( insertAtIndex ) ).offset().top;
1179 - jQuery( $children.get( insertAtIndex ) ).before( placeholder );
1180 - }
1181 - }
1182 -
1183 - top -= $list.offset().top;
1184 - placeholder.style.top = top + 'px';
1185 - }
1186 -
1187 - function determineIndexBasedOffOfMousePositionInList( $list, y ) {
1188 - const $items = $list.children().not( '.edit_field_type_end_divider' );
1189 - const length = $items.length;
1190 -
1191 - let index, item, itemTop, returnIndex;
1192 -
1193 - returnIndex = 0;
1194 - for ( index = length - 1; index >= 0; --index ) {
1195 - item = $items.get( index );
1196 - itemTop = jQuery( item ).offset().top;
1197 - if ( y > itemTop ) {
1198 - returnIndex = index;
1199 - if ( y > itemTop + ( jQuery( item ).outerHeight() / 2 ) ) {
1200 - returnIndex = index + 1;
1201 - }
1202 - break;
1203 - }
1204 - }
1205 -
1206 - return returnIndex;
1207 - }
1208 -
1209 - function handleDragOverFieldGroup({ droppable, x, placeholder }) {
1210 - const $row = jQuery( droppable );
1211 - const $children = getFieldsInRow( $row );
1212 -
1213 - if ( ! $children.length ) {
1214 - return;
1215 - }
1216 -
1217 - let left;
1218 - const insertAtIndex = determineIndexBasedOffOfMousePositionInRow( $row, x );
1219 -
1220 - if ( insertAtIndex === $children.length ) {
1221 - const $lastChild = jQuery( $children.get( insertAtIndex - 1 ) );
1222 - left = $lastChild.offset().left + $lastChild.outerWidth();
1223 - $row.append( placeholder );
1224 - } else {
1225 - left = jQuery( $children.get( insertAtIndex ) ).offset().left;
1226 - jQuery( $children.get( insertAtIndex ) ).before( placeholder );
1227 -
1228 - const amountToOffsetLeftBy = 0 === insertAtIndex ? 4 : 8; // Offset by 8 in between rows, but only 4 for the first item in a group.
1229 - left -= amountToOffsetLeftBy; // Offset the placeholder slightly so it appears between two fields.
1230 - }
1231 -
1232 - left -= $row.offset().left;
1233 -
1234 - placeholder.style.left = left + 'px';
1235 - }
1236 -
1237 - function syncAfterDragAndDrop() {
1238 - fixUnwrappedListItems();
1239 - toggleSectionHolder();
1240 - maybeFixEndDividers();
1241 - maybeDeleteEmptyFieldGroups();
1242 - updateFieldOrder();
1243 -
1244 - const event = new Event( 'frm_sync_after_drag_and_drop', { bubbles: false });
1245 - document.dispatchEvent( event );
1246 - }
1247 -
1248 - function maybeFixEndDividers() {
1249 - document.querySelectorAll( '.edit_field_type_end_divider' ).forEach(
1250 - endDivider => endDivider.parentNode.appendChild( endDivider )
1251 - );
1252 - }
1253 -
1254 - function maybeDeleteEmptyFieldGroups() {
1255 - document.querySelectorAll( 'li.form_field_box:not(.form-field)' ).forEach(
1256 - fieldGroup => ! fieldGroup.children.length && fieldGroup.remove()
1257 - );
1258 - }
1259 -
1260 - function fixUnwrappedListItems() {
1261 - const lists = document.querySelectorAll( 'ul#frm-show-fields, ul.start_divider' );
1262 - lists.forEach(
1263 - list => {
1264 - list.childNodes.forEach(
1265 - child => {
1266 - if ( 'undefined' === typeof child.classList ) {
1267 - return;
1268 - }
1269 -
1270 - if ( child.classList.contains( 'edit_field_type_end_divider' ) ) {
1271 - // Never wrap end divider in place.
1272 - return;
1273 - }
1274 -
1275 - if ( 'undefined' !== typeof child.classList && child.classList.contains( 'form-field' ) ) {
1276 - wrapFieldLiInPlace( child );
1277 - }
821 + if ( typeof ui.item.attr( 'id' ) !== 'undefined' ) {
822 + if ( ui.item.attr( 'id' ).indexOf( 'frm_field_id' ) > -1 ) {
823 + // An existing field was dragged and dropped into, out of, or between sections
824 + updateFieldAfterMovingBetweenSections( ui.item );
825 + } else {
826 + // A new field was dragged into the form
827 + insertNewFieldByDragging( this, ui.item, opts );
1278 828 }
1279 - );
1280 - }
1281 - );
1282 - }
1283 -
1284 - function deleteEmptyDividerWrappers() {
1285 - const dividers = document.querySelectorAll( 'ul.start_divider' );
1286 - if ( ! dividers.length ) {
1287 - return;
1288 - }
1289 - dividers.forEach(
1290 - function( divider ) {
1291 - const children = [].slice.call( divider.children );
1292 - children.forEach(
1293 - function( child ) {
1294 - if ( 0 === child.children.length ) {
1295 - child.remove();
1296 - } else if ( 1 === child.children.length && 'ul' === child.firstElementChild.nodeName.toLowerCase() && 0 === child.firstElementChild.children.length ) {
1297 - child.remove();
1298 - }
1299 - }
1300 - );
1301 - }
1302 - );
1303 - }
1304 -
1305 - function getFieldsInRow( $row ) {
1306 - let $fields = jQuery();
1307 -
1308 - const row = $row.get( 0 );
1309 - if ( ! row.children ) {
1310 - return $fields;
1311 - }
1312 -
1313 - Array.from( row.children ).forEach(
1314 - child => {
1315 - if ( 'none' === child.style.display ) {
1316 - return;
1317 829 }
1318 -
1319 - const classes = child.classList;
1320 - if ( ! classes.contains( 'form-field' ) || classes.contains( 'edit_field_type_end_divider' ) || classes.contains( 'frm-sortable-helper' ) ) {
1321 - return;
830 + },
831 + change: function( event, ui ) {
832 + // don't allow some field types inside section
833 + if ( allowDrop( ui ) ) {
834 + ui.placeholder.addClass( 'sortable-placeholder' ).removeClass( 'no-drop-placeholder' );
835 + cancelSort = false;
836 + } else {
837 + ui.placeholder.addClass( 'no-drop-placeholder' ).removeClass( 'sortable-placeholder' );
838 + cancelSort = true;
1322 839 }
1323 -
1324 - $fields = $fields.add( child );
1325 - }
1326 - );
1327 - return $fields;
1328 - }
1329 -
1330 - function determineIndexBasedOffOfMousePositionInRow( $row, x ) {
1331 - var $inputs = getFieldsInRow( $row ),
1332 - length = $inputs.length,
1333 - index, input, inputLeft, returnIndex;
1334 -
1335 - returnIndex = 0;
1336 - for ( index = length - 1; index >= 0; --index ) {
1337 - input = $inputs.get( index );
1338 - inputLeft = jQuery( input ).offset().left;
1339 - if ( x > inputLeft ) {
1340 - returnIndex = index;
1341 - if ( x > inputLeft + ( jQuery( input ).outerWidth() / 2 ) ) {
1342 - returnIndex = index + 1;
840 + },
841 + start: function( event, ui ) {
842 + if ( ui.item[0].offsetHeight > 120 ) {
843 + jQuery( sort ).sortable( 'refreshPositions' );
1343 844 }
1344 - break;
1345 - }
1346 - }
1347 -
1348 - return returnIndex;
1349 - }
1350 -
1351 - function syncLayoutClasses( $item, type ) {
1352 - var $fields, size, layoutClasses, classToAddFunction;
1353 -
1354 - if ( 'undefined' === typeof type ) {
1355 - type = 'even';
1356 - }
1357 -
1358 - $fields = $item.parent().children( 'li.form-field, li.frmbutton_loadingnow' ).not( '.edit_field_type_end_divider' );
1359 - size = $fields.length;
1360 - layoutClasses = getLayoutClasses();
1361 -
1362 - if ( 'even' === type && 5 !== size ) {
1363 - $fields.each( getSyncLayoutClass( layoutClasses, getEvenClassForSize( size ) ) );
1364 - } else if ( 'clear' === type ) {
1365 - $fields.each( getSyncLayoutClass( layoutClasses, '' ) );
1366 - } else {
1367 - if ( -1 !== [ 'left', 'right', 'middle', 'even' ].indexOf( type ) ) {
1368 - classToAddFunction = function( index ) {
1369 - return getClassForBlock( size, type, index );
1370 - };
1371 - } else {
1372 - classToAddFunction = function( index ) {
1373 - var size = type[ index ];
1374 - return getLayoutClassForSize( size );
1375 - };
1376 - }
1377 -
1378 - $fields.each( getSyncLayoutClass( layoutClasses, classToAddFunction ) );
1379 - }
1380 -
1381 - updateFieldGroupControls( $item.parent(), $fields.length );
1382 - }
1383 -
1384 - function updateFieldGroupControls( $row, count ) {
1385 - var rowOffset, shouldShowControls, controls;
1386 -
1387 - rowOffset = $row.offset();
1388 -
1389 - if ( 'undefined' === typeof rowOffset ) {
1390 - return;
1391 - }
1392 -
1393 - shouldShowControls = count >= 2;
1394 -
1395 - controls = document.getElementById( 'frm_field_group_controls' );
1396 - if ( null === controls ) {
1397 - if ( ! shouldShowControls ) {
1398 - // exit early. if we do not need controls and they do not exist, do nothing.
1399 - return;
1400 - }
1401 -
1402 - controls = div();
1403 - controls.id = 'frm_field_group_controls';
1404 - controls.setAttribute( 'role', 'group' );
1405 - controls.setAttribute( 'tabindex', 0 );
1406 - setFieldControlsHtml( controls );
1407 - document.getElementById( 'frm_builder_page' ).appendChild( controls );
1408 - }
1409 -
1410 - $row.append( controls );
1411 - controls.style.display = shouldShowControls ? 'block' : 'none';
1412 - }
1413 -
1414 - function setFieldControlsHtml( controls ) {
1415 - var layoutOption, moveOption;
1416 -
1417 - layoutOption = document.createElement( 'span' );
1418 - layoutOption.innerHTML = '<svg class="frmsvg"><use xlink:href="#frm_field_group_layout_icon"></use></svg>';
1419 - const layoutOptionLabel = __( 'Set Row Layout', 'formidable' );
1420 - addTooltip( layoutOption, layoutOptionLabel );
1421 - makeTabbable( layoutOption, layoutOptionLabel );
1422 -
1423 - moveOption = document.createElement( 'span' );
1424 - moveOption.innerHTML = '<svg class="frmsvg"><use xlink:href="#frm_thick_move_icon"></use></svg>';
1425 - moveOption.classList.add( 'frm-move' );
1426 - const moveOptionLabel = __( 'Move Field Group', 'formidable' );
1427 - addTooltip( moveOption, moveOptionLabel );
1428 - makeTabbable( moveOption, moveOptionLabel );
1429 -
1430 - controls.innerHTML = '';
1431 - controls.appendChild( layoutOption );
1432 - controls.appendChild( moveOption );
1433 - controls.appendChild( getFieldControlsDropdown() );
1434 - }
1435 -
1436 - function addTooltip( element, title ) {
1437 - element.setAttribute( 'data-toggle', 'tooltip' );
1438 - element.setAttribute( 'data-container', 'body' );
1439 - element.setAttribute( 'title', title );
1440 - element.addEventListener(
1441 - 'mouseover',
1442 - function() {
1443 - if ( null === element.getAttribute( 'data-original-title' ) ) {
1444 - jQuery( element ).tooltip();
845 + if ( ui.item[0].classList.contains( 'frm-page-collapsed' ) ) {
846 + // If a page if collapsed, expand it before dragging since only the page break will move.
847 + toggleCollapsePage( jQuery( ui.item[0]) );
1445 848 }
1446 - }
1447 - );
1448 - }
1449 -
1450 - function getFieldControlsDropdown() {
1451 - var dropdown, trigger, ul;
1452 -
1453 - dropdown = document.createElement( 'span' );
1454 - dropdown.classList.add( 'dropdown' );
1455 -
1456 - trigger = document.createElement( 'a' );
1457 - trigger.classList.add( 'frm_bstooltip', 'frm-hover-icon', 'frm-dropdown-toggle', 'dropdown-toggle' );
1458 - trigger.setAttribute( 'title', __( 'More Options', 'formidable' ) );
1459 - trigger.setAttribute( 'data-toggle', 'dropdown' );
1460 - trigger.setAttribute( 'data-container', 'body' );
1461 - makeTabbable( trigger, __( 'More Options', 'formidable' ) );
1462 - trigger.innerHTML = '<span><svg class="frmsvg"><use xlink:href="#frm_thick_more_vert_icon"></use></svg></span>';
1463 - dropdown.appendChild( trigger );
1464 -
1465 - ul = document.createElement( 'div' );
1466 - ul.classList.add( 'frm-dropdown-menu', 'dropdown-menu', 'dropdown-menu-right' );
1467 - ul.setAttribute( 'role', 'menu' );
1468 - dropdown.appendChild( ul );
1469 -
1470 - return dropdown;
1471 - }
1472 -
1473 - function getSyncLayoutClass( layoutClasses, classToAdd ) {
1474 - return function( itemIndex ) {
1475 - var currentClassToAdd, length, layoutClassIndex, currentClass, activeLayoutClass, fieldId, layoutClassesInput;
1476 -
1477 - currentClassToAdd = 'function' === typeof classToAdd ? classToAdd( itemIndex ) : classToAdd;
1478 - length = layoutClasses.length;
1479 - activeLayoutClass = false;
1480 - for ( layoutClassIndex = 0; layoutClassIndex < length; ++layoutClassIndex ) {
1481 - currentClass = layoutClasses[ layoutClassIndex ];
1482 - if ( this.classList.contains( currentClass ) ) {
1483 - activeLayoutClass = currentClass;
1484 - break;
849 + },
850 + helper: function( e, li ) {
851 + copyHelper = li.clone().insertAfter( li );
852 + return li.clone();
853 + },
854 + beforeStop: function( event, ui ) {
855 + // If this was dropped at the beginning of a collpased page, open it.
856 + var previous = ui.item[0].previousElementSibling;
857 + if ( previous !== null && previous.classList.contains( 'frm-page-collapsed' ) ) {
858 + toggleCollapsePage( jQuery( previous ) );
1485 859 }
1486 - }
1487 -
1488 - fieldId = this.dataset.fid;
1489 -
1490 - if ( 'undefined' === typeof fieldId ) {
1491 - // we are syncing the drag/drop placeholder before the actual field has loaded.
1492 - // this will get called again afterward and the input will exist then.
1493 - this.classList.add( currentClassToAdd );
1494 - return;
1495 - }
1496 -
1497 - moveFieldSettings( document.getElementById( 'frm-single-settings-' + fieldId ) );
1498 - layoutClassesInput = document.getElementById( 'frm_classes_' + fieldId );
1499 -
1500 - if ( null === layoutClassesInput ) {
1501 - // not every field type has a layout class input.
1502 - return;
1503 - }
1504 -
1505 - if ( false === activeLayoutClass ) {
1506 - if ( '' !== currentClassToAdd ) {
1507 - layoutClassesInput.value = layoutClassesInput.value.concat( ' ' + currentClassToAdd );
860 + },
861 + stop: function() {
862 + var moving = jQuery( this );
863 + copyHelper && copyHelper.remove();
864 + if ( cancelSort ) {
865 + moving.sortable( 'cancel' );
866 + } else {
867 + updateFieldOrder();
1508 868 }
1509 - } else {
1510 - this.classList.remove( activeLayoutClass );
1511 - layoutClassesInput.value = layoutClassesInput.value.replace( activeLayoutClass, currentClassToAdd );
1512 - }
869 + moving.children( '.edit_field_type_end_divider' ).appendTo( this );
870 + },
871 + sort: function( event ) {
872 + container.scrollTop( function( i, v ) {
873 + if ( startSort === false ) {
874 + startSort = event.clientY;
875 + return v;
876 + }
1513 877
1514 - if ( this.classList.contains( 'frm_first' ) ) {
1515 - this.classList.remove( 'frm_first' );
1516 - layoutClassesInput.value = layoutClassesInput.value.replace( 'frm_first', '' ).trim();
878 + var moved = event.clientY - startSort;
879 + var h = this.offsetHeight;
880 + var relativePos = event.clientY - this.offsetTop;
881 + var y = relativePos - h / 2;
882 + if ( relativePos > ( h - 50 ) && moved > 5 ) {
883 + // scrolling down
884 + return v + y * 0.1;
885 + } else if ( relativePos < 50 && moved < -5 ) {
886 + //scrolling up
887 + return v - Math.abs( y * 0.1 );
888 + }
889 + });
1517 890 }
891 + };
1518 892
1519 - if ( 0 === itemIndex ) {
1520 - this.classList.add( 'frm_first' );
1521 - layoutClassesInput.value = layoutClassesInput.value.concat( ' frm_first' );
1522 - }
893 + jQuery( sort ).sortable( opts );
1523 894
1524 - jQuery( layoutClassesInput ).trigger( 'change' );
1525 - };
895 + setupFieldOptionSorting( jQuery( '#frm_builder_page' ) );
1526 896 }
1527 897
1528 - function getLayoutClasses() {
1529 - return [ 'frm_full', 'frm_half', 'frm_third', 'frm_fourth', 'frm_sixth', 'frm_two_thirds', 'frm_three_fourths', 'frm1', 'frm2', 'frm3', 'frm4', 'frm5', 'frm6', 'frm7', 'frm8', 'frm9', 'frm10', 'frm11', 'frm12' ];
1530 - }
1531 -
1532 898 function setupFieldOptionSorting( sort ) {
1533 899 var opts = {
1534 900 items: '.frm_sortable_field_opts li',
1535 901 axis: 'y',
@@ -1545,8 +911,9 @@
1545 911 var fieldId = ui.item.attr( 'id' ).replace( 'frm_delete_field_', '' ).replace( '-' + ui.item.data( 'optkey' ) + '_container', '' );
1546 912 resetDisplayedOpts( fieldId );
1547 913 }
1548 914 };
915 +
1549 916 jQuery( sort ).sortable( opts );
1550 917 }
1551 918
1552 919 // Get the section where a field is dropped
@@ -1551,11 +918,12 @@
1551 918
1552 919 // Get the section where a field is dropped
1553 920 function getSectionForFieldPlacement( currentItem ) {
1554 921 var section = '';
1555 - if ( typeof currentItem !== 'undefined' && ! currentItem.hasClass( 'edit_field_type_divider' ) ) {
922 + if ( typeof currentItem !== 'undefined' ) {
1556 923 section = currentItem.closest( '.edit_field_type_divider' );
1557 924 }
925 +
1558 926 return section;
1559 927 }
1560 928
1561 929 // Get the form ID where a field is dropped
@@ -1590,38 +958,23 @@
1590 958
1591 959 /**
1592 960 * Update a field after it is dragged and dropped into, out of, or between sections
1593 961 *
1594 - * @param {Object} currentItem
1595 - * @param {Object} previousSection
1596 - * @returns {void}
962 + * @param {object} currentItem
1597 963 */
1598 - function updateFieldAfterMovingBetweenSections( currentItem, previousSection ) {
1599 - if ( ! currentItem.hasClass( 'form-field' ) ) {
1600 - // currentItem is a field group. Call for children recursively.
1601 - getFieldsInRow( jQuery( currentItem.get( 0 ).firstChild ) ).each(
1602 - function() {
1603 - updateFieldAfterMovingBetweenSections( jQuery( this ), previousSection );
1604 - }
1605 - );
1606 - return;
1607 - }
964 + function updateFieldAfterMovingBetweenSections( currentItem ) {
965 + var fieldId = currentItem.attr( 'id' ).replace( 'frm_field_id_', '' );
966 + var section = getSectionForFieldPlacement( currentItem );
967 + var formId = getFormIdForFieldPlacement( section );
968 + var sectionId = getSectionIdForFieldPlacement( section );
1608 969
1609 - const fieldId = currentItem.attr( 'id' ).replace( 'frm_field_id_', '' );
1610 - const section = getSectionForFieldPlacement( currentItem );
1611 - const formId = getFormIdForFieldPlacement( section );
1612 - const sectionId = getSectionIdForFieldPlacement( section );
1613 - const previousFormId = previousSection ? getFormIdForFieldPlacement( jQuery( previousSection.parentNode ) ) : 0;
1614 -
1615 970 jQuery.ajax({
1616 - type: 'POST',
1617 - url: ajaxurl,
971 + type: 'POST', url: ajaxurl,
1618 972 data: {
1619 973 action: 'frm_update_field_after_move',
1620 974 form_id: formId,
1621 975 field: fieldId,
1622 976 section_id: sectionId,
1623 - previous_form_id: previousFormId,
1624 977 nonce: frmGlobal.nonce
1625 978 },
1626 979 success: function() {
1627 980 toggleSectionHolder();
@@ -1637,32 +990,33 @@
1637 990
1638 991 /**
1639 992 * Add a new field by dragging and dropping it from the Fields sidebar
1640 993 *
1641 - * @param {string} fieldType
994 + * @param {object} selectedItem
995 + * @param {object} fieldButton
996 + * @param {object} opts
1642 997 */
1643 - function insertNewFieldByDragging( fieldType ) {
1644 - const placeholder = document.getElementById( 'frm_drag_placeholder' );
1645 - const loadingID = fieldType.replace( '|', '-' ) + '_' + getAutoId();
1646 - const loading = tag(
1647 - 'li',
1648 - {
1649 - id: loadingID,
1650 - className: 'frm-wait frmbutton_loadingnow'
1651 - }
1652 - );
1653 - const $placeholder = jQuery( loading );
1654 - const currentItem = jQuery( placeholder );
1655 - const section = getSectionForFieldPlacement( currentItem );
1656 - const formId = getFormIdForFieldPlacement( section );
1657 - const sectionId = getSectionIdForFieldPlacement( section );
998 + function insertNewFieldByDragging( selectedItem, fieldButton ) {
999 + var fieldType, addBtn, currentItem, section, formId, sectionId, loadingID, hasBreak;
1658 1000
1659 - placeholder.parentNode.insertBefore( loading, placeholder );
1660 - placeholder.remove();
1661 - syncLayoutClasses( $placeholder );
1001 + fieldType = fieldButton.attr( 'id' );
1662 1002
1663 - let hasBreak = 0;
1003 + // We'll optimistically disable the button now. We'll re-enable if AJAX fails
1664 1004 if ( 'summary' === fieldType ) {
1005 + addBtn = fieldButton.children( '.frm_add_field' );
1006 + disableSummaryBtnBeforeAJAX( addBtn, fieldButton );
1007 + }
1008 +
1009 + currentItem = jQuery( selectedItem ).data().uiSortable.currentItem;
1010 + section = getSectionForFieldPlacement( currentItem );
1011 + formId = getFormIdForFieldPlacement( section );
1012 + sectionId = getSectionIdForFieldPlacement( section );
1013 +
1014 + loadingID = fieldType.replace( '|', '-' ) + '_' + getAutoId();
1015 + currentItem.replaceWith( '<li class="frm-wait frmbutton_loadingnow" id="' + loadingID + '" ></li>' );
1016 +
1017 + hasBreak = 0;
1018 + if ( 'summary' === fieldType ) {
1665 1019 // see if we need to insert a page break before this newly-added summary field. Check for at least 1 page break
1666 1020 hasBreak = jQuery( '.frmbutton_loadingnow#' + loadingID ).prevAll( 'li[data-type="break"]' ).length ? 1 : 0;
1667 1021 }
1668 1022
@@ -1676,65 +1030,20 @@
1676 1030 nonce: frmGlobal.nonce,
1677 1031 has_break: hasBreak
1678 1032 },
1679 1033 success: function( msg ) {
1680 - let replaceWith;
1681 1034 document.getElementById( 'frm_form_editor_container' ).classList.add( 'frm-has-fields' );
1682 - const $siblings = $placeholder.siblings( 'li.form-field' ).not( '.edit_field_type_end_divider' );
1683 - if ( ! $siblings.length ) {
1684 - // if dragging into a new row, we need to wrap the li first.
1685 - replaceWith = wrapFieldLi( msg );
1686 - } else {
1687 - replaceWith = msgAsjQueryObject( msg );
1688 - if ( ! $placeholder.get( 0 ).parentNode.parentNode.classList.contains( 'ui-draggable' ) ) {
1689 - // If a field group wasn't draggable because it only had a single field, make it draggable.
1690 - makeDraggable( $placeholder.get( 0 ).parentNode.parentNode, '.frm-move' );
1691 - }
1692 - }
1693 - $placeholder.replaceWith( replaceWith );
1035 + jQuery( '.frmbutton_loadingnow#' + loadingID ).replaceWith( msg );
1694 1036 updateFieldOrder();
1037 +
1695 1038 afterAddField( msg, false );
1696 - if ( $siblings.length ) {
1697 - syncLayoutClasses( $siblings.first() );
1698 - }
1699 - toggleSectionHolder();
1700 -
1701 - if ( ! $siblings.length ) {
1702 - makeDroppable( replaceWith.get( 0 ).querySelector( 'ul.frm_sorting' ) );
1703 - makeDraggable( replaceWith.get( 0 ).querySelector( 'li.form-field' ), '.frm-move' );
1704 - } else {
1705 - makeDraggable( replaceWith.get( 0 ), '.frm-move' );
1706 - }
1707 -
1708 1039 },
1709 - error: handleInsertFieldError
1040 + error: function( jqXHR, textStatus, errorThrown ) {
1041 + maybeReenableSummaryBtnAfterAJAX( fieldType, addBtn, fieldButton, errorThrown );
1042 + }
1710 1043 });
1711 1044 }
1712 1045
1713 - function moveFieldThatAlreadyExists( draggable, placeholder ) {
1714 - placeholder.parentNode.insertBefore( draggable, placeholder );
1715 - }
1716 -
1717 - function msgAsjQueryObject( msg ) {
1718 - const element = div();
1719 - element.innerHTML = msg;
1720 - return jQuery( element.firstChild );
1721 - }
1722 -
1723 - function handleInsertFieldError( jqXHR, _, errorThrown ) {
1724 - maybeShowInsertFieldError( errorThrown, jqXHR );
1725 - }
1726 -
1727 - function maybeShowInsertFieldError( errorThrown, jqXHR ) {
1728 - if ( ! jqXHRAborted( jqXHR ) ) {
1729 - infoModal( errorThrown + '. Please try again.' );
1730 - }
1731 - }
1732 -
1733 - function jqXHRAborted( jqXHR ) {
1734 - return jqXHR.status === 0 || jqXHR.readyState === 0;
1735 - }
1736 -
1737 1046 /**
1738 1047 * Get a unique id that automatically increments with every function call.
1739 1048 * Can be used for any UI that requires a unique id.
1740 1049 * Not to be used in data.
@@ -1744,178 +1053,35 @@
1744 1053 function getAutoId() {
1745 1054 return ++autoId;
1746 1055 }
1747 1056
1748 - // Don't allow page break, embed form, or section inside section field
1749 - // Don't allow page breaks inside of field groups.
1750 - // Don't allow field groups with sections inside of sections.
1751 - // Don't allow field groups in field groups.
1752 - // Don't allow hidden fields inside of field groups but allow them in sections.
1753 - function allowDrop( draggable, droppable ) {
1754 - if ( false === droppable ) {
1755 - // Don't show drop placeholder if dragging somewhere off of the droppable area.
1756 - return false;
1757 - }
1758 -
1759 - if ( droppable.closest( '.frm-sortable-helper' ) ) {
1760 - // Do not allow drop into draggable.
1761 - return false;
1762 - }
1763 -
1764 - if ( 'frm-show-fields' === droppable.id ) {
1765 - // Everything can be dropped into the main list of fields.
1057 + // don't allow page break, embed form, captcha, summary, or section inside section field
1058 + function allowDrop( ui ) {
1059 + if ( ! ui.placeholder.parent().hasClass( 'start_divider' ) ) {
1766 1060 return true;
1767 1061 }
1768 1062
1769 - if ( ! droppable.classList.contains( 'start_divider' ) ) {
1770 - const $fieldsInRow = getFieldsInRow( jQuery( droppable ) );
1771 - if ( ! groupCanFitAnotherField( $fieldsInRow, jQuery( draggable ) ) ) {
1772 - // Field group is full and cannot accept another field.
1063 + // new field
1064 + if ( ui.item.hasClass( 'frmbutton' ) ) {
1065 + if ( ui.item.hasClass( 'frm_tbreak' ) || ui.item.hasClass( 'frm_tform' ) || ui.item.hasClass( 'frm_tdivider' ) || ui.item.hasClass( 'frm_tdivider-repeat' ) ) {
1773 1066 return false;
1774 1067 }
1775 - }
1776 -
1777 - const isNewField = draggable.classList.contains( 'frm-new-field' );
1778 - if ( isNewField ) {
1779 - return allowNewFieldDrop( draggable, droppable );
1780 - }
1781 -
1782 - return allowMoveField( draggable, droppable );
1783 - }
1784 -
1785 - // Don't allow a new page break or hidden field in a field group.
1786 - // Don't allow a new field into a field group that includes a page break or hidden field.
1787 - // Don't allow a new section inside of a section.
1788 - // Don't allow an embedded form in a section.
1789 - function allowNewFieldDrop( draggable, droppable ) {
1790 - const classes = draggable.classList;
1791 - const newPageBreakField = classes.contains( 'frm_tbreak' );
1792 - const newHiddenField = classes.contains( 'frm_thidden' );
1793 - const newSectionField = classes.contains( 'frm_tdivider' );
1794 - const newEmbedField = classes.contains( 'frm_tform' );
1795 -
1796 - const newFieldWillBeAddedToAGroup = ! ( 'frm-show-fields' === droppable.id || droppable.classList.contains( 'start_divider' ) );
1797 - if ( newFieldWillBeAddedToAGroup ) {
1798 - if ( groupIncludesBreakOrHidden( droppable ) ) {
1799 - // Never allow any field beside a page break or a hidden field.
1800 - return false;
1801 - }
1802 -
1803 - return ! newHiddenField && ! newPageBreakField;
1804 - }
1805 -
1806 - const fieldTypeIsAlwaysAllowed = ! newPageBreakField && ! newHiddenField && ! newSectionField && ! newEmbedField;
1807 - if ( fieldTypeIsAlwaysAllowed ) {
1808 1068 return true;
1809 1069 }
1810 1070
1811 - const newFieldWillBeAddedToASection = droppable.classList.contains( 'start_divider' ) || null !== droppable.closest( '.start_divider' );
1812 - if ( newFieldWillBeAddedToASection ) {
1813 - // Don't allow a section or an embedded form in a section.
1814 - return ! newEmbedField && ! newSectionField;
1815 - }
1816 -
1817 - return true;
1071 + // moving an existing field
1072 + return ! ( ui.item.hasClass( 'edit_field_type_break' ) || ui.item.hasClass( 'edit_field_type_form' ) ||
1073 + ui.item.hasClass( 'edit_field_type_divider' ) );
1818 1074 }
1819 1075
1820 - function allowMoveField( draggable, droppable ) {
1821 - if ( isFieldGroup( draggable ) ) {
1822 - return allowMoveFieldGroup( draggable, droppable );
1823 - }
1076 + function loadFields( fieldId ) {
1077 + var addHtmlToField, nextElement,
1078 + thisField = document.getElementById( fieldId ),
1079 + $thisField = jQuery( thisField ),
1080 + field = [];
1824 1081
1825 - const isPageBreak = draggable.classList.contains( 'edit_field_type_break' );
1826 - if ( isPageBreak ) {
1827 - // Page breaks are only allowed in the main list of fields, not in sections or in field groups.
1828 - return false;
1829 - }
1830 -
1831 - if ( droppable.classList.contains( 'start_divider' ) ) {
1832 - return allowMoveFieldToSection( draggable );
1833 - }
1834 -
1835 - const isHiddenField = draggable.classList.contains( 'edit_field_type_hidden' );
1836 - if ( isHiddenField ) {
1837 - // Hidden fields should not be added to field groups since they're not shown and don't make sense with the grid distribution.
1838 - return false;
1839 - }
1840 -
1841 - return allowMoveFieldToGroup( draggable, droppable );
1842 - }
1843 -
1844 - function isFieldGroup( draggable ) {
1845 - return draggable.classList.contains( 'frm_field_box' ) && ! draggable.classList.contains( 'form-field' );
1846 - }
1847 -
1848 - function allowMoveFieldGroup( fieldGroup, droppable ) {
1849 - if ( droppable.classList.contains( 'start_divider' ) && null === fieldGroup.querySelector( '.start_divider' ) ) {
1850 - // Allow a field group with no section inside of a section.
1851 - return true;
1852 - }
1853 - return false;
1854 - }
1855 -
1856 - function allowMoveFieldToSection( draggable ) {
1857 - const draggableIncludeEmbedForm = draggable.classList.contains( 'edit_field_type_form' ) || draggable.querySelector( '.edit_field_type_form' );
1858 - if ( draggableIncludeEmbedForm ) {
1859 - // Do not allow an embedded form inside of a section.
1860 - return false;
1861 - }
1862 -
1863 - const draggableIncludesSection = draggable.classList.contains( 'edit_field_type_divider' ) || draggable.querySelector( '.edit_field_type_divider' );
1864 - if ( draggableIncludesSection ) {
1865 - // Do not allow a section inside of a section.
1866 - return false;
1867 - }
1868 -
1869 - return true;
1870 - }
1871 -
1872 - function allowMoveFieldToGroup( draggable, group ) {
1873 - if ( groupIncludesBreakOrHidden( group ) ) {
1874 - // Never allow any field beside a page break or a hidden field.
1875 - return false;
1876 - }
1877 -
1878 - const isFieldGroup = jQuery( draggable ).children( 'ul.frm_sorting' ).not( '.start_divider' ).length > 0;
1879 - if ( isFieldGroup ) {
1880 - // Do not allow a field group directly inside of a field group unless it's in a section.
1881 - return false;
1882 - }
1883 -
1884 - const draggableIncludesASection = draggable.classList.contains( 'edit_field_type_divider' ) || draggable.querySelector( '.edit_field_type_divider' );
1885 - const draggableIsEmbedField = draggable.classList.contains( 'edit_field_type_form' );
1886 - const groupIsInASection = null !== group.closest( '.start_divider' );
1887 - if ( groupIsInASection && ( draggableIncludesASection || draggableIsEmbedField ) ) {
1888 - // Do not allow a section or an embed field inside of a section.
1889 - return false;
1890 - }
1891 -
1892 - return true;
1893 - }
1894 -
1895 - function groupIncludesBreakOrHidden( group ) {
1896 - return null !== group.querySelector( '.edit_field_type_break, .edit_field_type_hidden' );
1897 - }
1898 -
1899 - function groupCanFitAnotherField( fieldsInRow, $field ) {
1900 - var fieldId;
1901 - if ( fieldsInRow.length < 6 ) {
1902 - return true;
1903 - }
1904 - if ( fieldsInRow.length > 6 ) {
1905 - return false;
1906 - }
1907 - fieldId = $field.attr( 'data-fid' );
1908 - // allow 6 if we're not changing field groups.
1909 - return 1 === jQuery( fieldsInRow ).filter( '[data-fid="' + fieldId + '"]' ).length;
1910 - }
1911 -
1912 - function loadFields( fieldId ) {
1913 - const thisField = document.getElementById( fieldId );
1914 - const $thisField = jQuery( thisField );
1915 - const field = [];
1916 - const addHtmlToField = element => {
1917 - const frmHiddenFdata = element.querySelector( '.frm_hidden_fdata' );
1082 + addHtmlToField = function( element ) {
1083 + var frmHiddenFdata = element.querySelector( '.frm_hidden_fdata' );
1918 1084 element.classList.add( 'frm_load_now' );
1919 1085 if ( frmHiddenFdata !== null ) {
1920 1086 field.push( frmHiddenFdata.innerHTML );
1921 1087 }
@@ -1920,9 +1086,9 @@
1920 1086 field.push( frmHiddenFdata.innerHTML );
1921 1087 }
1922 1088 };
1923 1089
1924 - let nextElement = thisField;
1090 + nextElement = thisField;
1925 1091 addHtmlToField( nextElement );
1926 1092 while ( nextElement.nextElementSibling && field.length < 15 ) {
1927 1093 addHtmlToField( nextElement.nextElementSibling );
1928 1094 nextElement = nextElement.nextElementSibling;
@@ -1928,10 +1094,9 @@
1928 1094 nextElement = nextElement.nextElementSibling;
1929 1095 }
1930 1096
1931 1097 jQuery.ajax({
1932 - type: 'POST',
1933 - url: ajaxurl,
1098 + type: 'POST', url: ajaxurl,
1934 1099 data: {
1935 1100 action: 'frm_load_field',
1936 1101 field: field,
1937 1102 form_id: thisFormId,
@@ -1936,65 +1101,63 @@
1936 1101 field: field,
1937 1102 form_id: thisFormId,
1938 1103 nonce: frmGlobal.nonce
1939 1104 },
1940 - success: html => handleAjaxLoadFieldSuccess( html, $thisField, field )
1941 - });
1942 - }
1105 + success: function( html ) {
1106 + var key, $nextSet;
1943 1107
1944 - function handleAjaxLoadFieldSuccess( html, $thisField, field ) {
1945 - let key, $nextSet;
1108 + html = html.replace( /^\s+|\s+$/g, '' );
1109 + if ( html.indexOf( '{' ) !== 0 ) {
1110 + jQuery( '.frm_load_now' ).removeClass( '.frm_load_now' ).html( 'Error' );
1111 + return;
1112 + }
1946 1113
1947 - html = html.replace( /^\s+|\s+$/g, '' );
1948 - if ( html.indexOf( '{' ) !== 0 ) {
1949 - jQuery( '.frm_load_now' ).removeClass( '.frm_load_now' ).html( 'Error' );
1950 - return;
1951 - }
1114 + html = JSON.parse( html );
1952 1115
1953 - html = JSON.parse( html );
1954 - for ( key in html ) {
1955 - jQuery( '#frm_field_id_' + key ).replaceWith( html[key]);
1956 - setupSortable( '#frm_field_id_' + key + '.edit_field_type_divider ul.frm_sorting' );
1957 - makeDraggable( document.getElementById( 'frm_field_id_' + key ) );
1958 - }
1116 + for ( key in html ) {
1117 + jQuery( '#frm_field_id_' + key ).replaceWith( html[key]);
1118 + setupSortable( '#frm_field_id_' + key + '.edit_field_type_divider ul.frm_sorting' );
1119 + }
1959 1120
1960 - $nextSet = $thisField.nextAll( '.frm_field_loading:not(.frm_load_now)' );
1961 - if ( $nextSet.length ) {
1962 - loadFields( $nextSet.attr( 'id' ) );
1963 - } else {
1964 - // go up a level
1965 - $nextSet = jQuery( document.getElementById( 'frm-show-fields' ) ).find( '.frm_field_loading:not(.frm_load_now)' );
1966 - if ( $nextSet.length ) {
1967 - loadFields( $nextSet.attr( 'id' ) );
1121 + $nextSet = $thisField.nextAll( '.frm_field_loading:not(.frm_load_now)' );
1122 + if ( $nextSet.length ) {
1123 + loadFields( $nextSet.attr( 'id' ) );
1124 + } else {
1125 + // go up a level
1126 + $nextSet = jQuery( document.getElementById( 'frm-show-fields' ) ).find( '.frm_field_loading:not(.frm_load_now)' );
1127 + if ( $nextSet.length ) {
1128 + loadFields( $nextSet.attr( 'id' ) );
1129 + }
1130 + }
1131 +
1132 + initiateMultiselect();
1133 + renumberPageBreaks();
1134 + maybeHideQuantityProductFieldOption();
1968 1135 }
1969 - }
1970 -
1971 - initiateMultiselect();
1972 - renumberPageBreaks();
1973 - maybeHideQuantityProductFieldOption();
1974 -
1975 - const loadedEvent = new Event( 'frm_ajax_loaded_field', { bubbles: false });
1976 - loadedEvent.frmFields = field.map( f => JSON.parse( f ) );
1977 - document.dispatchEvent( loadedEvent );
1136 + });
1978 1137 }
1979 1138
1980 1139 function addFieldClick() {
1981 1140 /*jshint validthis:true */
1982 - const $thisObj = jQuery( this );
1141 + var $thisObj = jQuery( this );
1983 1142 // there is no real way to disable a <a> (with a valid href attribute) in HTML - https://css-tricks.com/how-to-disable-links/
1984 1143 if ( $thisObj.hasClass( 'disabled' ) ) {
1985 1144 return false;
1986 1145 }
1987 1146
1988 - const $button = $thisObj.closest( '.frmbutton' );
1989 - const fieldType = $button.attr( 'id' );
1147 + var $button = $thisObj.closest( '.frmbutton' );
1148 + var fieldType = $button.attr( 'id' );
1990 1149
1991 - let hasBreak = 0;
1150 + var hasBreak = 0;
1992 1151 if ( 'summary' === fieldType ) {
1152 + // We'll optimistically disable $button now. We'll re-enable if AJAX fails
1153 + disableSummaryBtnBeforeAJAX( $thisObj, $button );
1154 +
1993 1155 hasBreak = $newFields.children( 'li[data-type="break"]' ).length > 0 ? 1 : 0;
1994 1156 }
1995 1157
1996 - const formId = thisFormId;
1158 + var formId = thisFormId;
1159 +
1997 1160 jQuery.ajax({
1998 1161 type: 'POST',
1999 1162 url: ajaxurl,
2000 1163 data: {
@@ -2006,24 +1169,57 @@
2006 1169 has_break: hasBreak
2007 1170 },
2008 1171 success: function( msg ) {
2009 1172 document.getElementById( 'frm_form_editor_container' ).classList.add( 'frm-has-fields' );
2010 - const replaceWith = wrapFieldLi( msg );
2011 - $newFields.append( replaceWith );
1173 + $newFields.append( msg );
2012 1174 afterAddField( msg, true );
2013 -
2014 - replaceWith.each(
2015 - function() {
2016 - makeDroppable( this.querySelector( 'ul.frm_sorting' ) );
2017 - makeDraggable( this.querySelector( '.form-field' ), '.frm-move' );
2018 - }
2019 - );
2020 1175 },
2021 - error: handleInsertFieldError
1176 + error: function( jqXHR, textStatus, errorThrown ) {
1177 + maybeReenableSummaryBtnAfterAJAX( fieldType, $thisObj, $button, errorThrown );
1178 + }
2022 1179 });
2023 1180 return false;
2024 1181 }
2025 1182
1183 + function disableSummaryBtnBeforeAJAX( addBtn, fieldButton ) {
1184 + addBtn.addClass( 'disabled' );
1185 + fieldButton.draggable( 'disable' );
1186 + }
1187 +
1188 + function reenableAddSummaryBtn() {
1189 + var frmBtn = jQuery( 'li#summary' );
1190 + var addFieldLink = frmBtn.children( '.frm_add_field' );
1191 + frmBtn.draggable( 'enable' );
1192 + addFieldLink.removeClass( 'disabled' );
1193 + }
1194 +
1195 + function maybeDisableAddSummaryBtn() {
1196 + var summary = document.getElementById( 'summary' );
1197 + if ( summary && ! summary.classList.contains( 'frm_show_upgrade' ) && formHasSummaryField() ) {
1198 + disableAddSummaryBtn();
1199 + }
1200 + }
1201 +
1202 + function disableAddSummaryBtn() {
1203 + var frmBtn = jQuery( 'li#summary' );
1204 + var addFieldLink = frmBtn.children( '.frm_add_field' );
1205 + frmBtn.draggable( 'disable' );
1206 + addFieldLink.addClass( 'disabled' );
1207 + }
1208 +
1209 + function maybeReenableSummaryBtnAfterAJAX( fieldType, addBtn, fieldButton, errorThrown ) {
1210 + infoModal( errorThrown + '. Please try again.' );
1211 + if ( 'summary' === fieldType ) {
1212 + addBtn.removeClass( 'disabled' );
1213 + fieldButton.draggable( 'enable' );
1214 + }
1215 + }
1216 +
1217 + function formHasSummaryField() {
1218 + // .edit_field_type_summary is a better selector here in order to also cover fields loaded by AJAX
1219 + return $newFields.children( 'li.edit_field_type_summary' ).length > 0;
1220 + }
1221 +
2026 1222 function maybeHideQuantityProductFieldOption() {
2027 1223 var hide = true,
2028 1224 opts = document.querySelectorAll( '.frmjs_prod_field_opt_cont' );
2029 1225
@@ -2040,25 +1236,17 @@
2040 1236 }
2041 1237 }
2042 1238
2043 1239 function duplicateField() {
2044 - var $field, fieldId, children, newRowId, fieldOrder;
1240 + /*jshint validthis:true */
1241 + var thisField = jQuery( this ).closest( 'li' );
1242 + var fieldId = thisField.data( 'fid' );
1243 + var children = fieldsInSection( fieldId );
2045 1244
2046 - $field = jQuery( this ).closest( 'li.form-field' );
2047 -
2048 - if ( $field.hasClass( 'frm-page-collapsed' ) ) {
1245 + if ( thisField.hasClass( 'frm-section-collapsed' ) || thisField.hasClass( 'frm-page-collapsed' ) ) {
2049 1246 return false;
2050 1247 }
2051 1248
2052 - closeOpenFieldDropdowns();
2053 - fieldId = $field.data( 'fid' );
2054 - children = fieldsInSection( fieldId );
2055 - newRowId = this.getAttribute( 'frm-target-row-id' );
2056 -
2057 - if ( null !== newRowId ) {
2058 - fieldOrder = this.getAttribute( 'frm-field-order' );
2059 - }
2060 -
2061 1249 jQuery.ajax({
2062 1250 type: 'POST',
2063 1251 url: ajaxurl,
2064 1252 data: {
@@ -2068,363 +1256,24 @@
2068 1256 children: children,
2069 1257 nonce: frmGlobal.nonce
2070 1258 },
2071 1259 success: function( msg ) {
2072 - var newRow;
2073 -
2074 - let replaceWith;
2075 -
2076 - if ( null !== newRowId ) {
2077 - newRow = document.getElementById( newRowId );
2078 - if ( null !== newRow ) {
2079 - replaceWith = msgAsjQueryObject( msg );
2080 - jQuery( newRow ).append( replaceWith );
2081 - makeDraggable( replaceWith.get( 0 ), '.frm-move' );
2082 - if ( null !== fieldOrder ) {
2083 - newRow.lastElementChild.setAttribute( 'frm-field-order', fieldOrder );
2084 - }
2085 - jQuery( newRow ).trigger(
2086 - 'frm_added_duplicated_field_to_row',
2087 - {
2088 - duplicatedFieldHtml: msg,
2089 - originalFieldId: fieldId
2090 - }
2091 - );
2092 - afterAddField( msg, false );
2093 - return;
2094 - }
2095 - }
2096 -
2097 - if ( $field.siblings( 'li.form-field' ).length ) {
2098 - replaceWith = msgAsjQueryObject( msg );
2099 - $field.after( replaceWith );
2100 - syncLayoutClasses( $field );
2101 - makeDraggable( replaceWith.get( 0 ), '.frm-move' );
2102 - } else {
2103 - replaceWith = wrapFieldLi( msg );
2104 - $field.parent().parent().after( replaceWith );
2105 - makeDroppable( replaceWith.get( 0 ).querySelector( 'ul.frm_sorting' ) );
2106 - makeDraggable( replaceWith.get( 0 ).querySelector( 'li.form-field' ), '.frm-move' );
2107 - }
2108 -
1260 + thisField.after( msg );
2109 1261 updateFieldOrder();
2110 1262 afterAddField( msg, false );
2111 - maybeDuplicateUnsavedSettings( fieldId, msg );
2112 - toggleOneSectionHolder( replaceWith.find( '.start_divider' ) );
2113 - $field[0].querySelector( '.frm-dropdown-menu.dropdown-menu-right' )?.classList.remove( 'show' );
2114 1263 }
2115 1264 });
2116 1265 return false;
2117 1266 }
2118 1267
2119 - function maybeDuplicateUnsavedSettings( originalFieldId, newFieldHtml ) {
2120 - var originalSettings, newFieldId, copySettings, fieldOptionKeys, originalDefault, copyDefault;
2121 -
2122 - originalSettings = document.getElementById( 'frm-single-settings-' + originalFieldId );
2123 - if ( null === originalSettings ) {
2124 - return;
2125 - }
2126 -
2127 - newFieldId = jQuery( newFieldHtml ).attr( 'data-fid' );
2128 - if ( 'undefined' === typeof newFieldId ) {
2129 - return;
2130 - }
2131 -
2132 - copySettings = document.getElementById( 'frm-single-settings-' + newFieldId );
2133 - if ( null === copySettings ) {
2134 - return;
2135 - }
2136 -
2137 - fieldOptionKeys = [
2138 - 'name', 'required', 'unique', 'read_only', 'placeholder', 'description', 'size', 'max', 'format', 'prepend', 'append', 'separate_value'
2139 - ];
2140 -
2141 - originalSettings.querySelectorAll( 'input[name^="field_options["], textarea[name^="field_options["]' ).forEach(
2142 - function( originalSetting ) {
2143 - var key, tagType, copySetting;
2144 -
2145 - key = getKeyFromSettingInput( originalSetting );
2146 -
2147 - if ( 'options' === key ) {
2148 - copyOption( originalSetting, copySettings, originalFieldId, newFieldId );
2149 - return;
2150 - }
2151 -
2152 - if ( -1 === fieldOptionKeys.indexOf( key ) ) {
2153 - return;
2154 - }
2155 -
2156 - tagType = originalSetting.matches( 'input' ) ? 'input' : 'textarea';
2157 - copySetting = copySettings.querySelector( tagType + '[name="field_options[' + key + '_' + newFieldId + ']"]' );
2158 - if ( null === copySetting ) {
2159 - return;
2160 - }
2161 -
2162 - if ( 'checkbox' === originalSetting.type ) {
2163 - if ( originalSetting.checked !== copySetting.checked ) {
2164 - jQuery( copySetting ).trigger( 'click' );
2165 - }
2166 - } else if ( 'text' === originalSetting.type || 'textarea' === tagType ) {
2167 - if ( originalSetting.value !== copySetting.value ) {
2168 - copySetting.value = originalSetting.value;
2169 - jQuery( copySetting ).trigger( 'change' );
2170 - }
2171 - }
2172 - }
2173 - );
2174 -
2175 - originalDefault = originalSettings.querySelector( 'input[name="default_value_' + originalFieldId + '"]' );
2176 - if ( null !== originalDefault ) {
2177 - copyDefault = copySettings.querySelector( 'input[name="default_value_' + newFieldId + '"]' );
2178 - if ( null !== copyDefault && originalDefault.value !== copyDefault.value ) {
2179 - copyDefault.value = originalDefault.value;
2180 - jQuery( copyDefault ).trigger( 'change' );
2181 - }
2182 - }
2183 - }
2184 -
2185 - function copyOption( originalSetting, copySettings, originalFieldId, newFieldId ) {
2186 - var remainingKeyDetails, copyKey, copySetting;
2187 - remainingKeyDetails = originalSetting.name.substr( 23 + ( '' + originalFieldId ).length );
2188 - copyKey = 'field_options[options_' + newFieldId + ']' + remainingKeyDetails;
2189 - copySetting = copySettings.querySelector( 'input[name="' + copyKey + '"]' );
2190 - if ( null !== copySetting && copySetting.value !== originalSetting.value ) {
2191 - copySetting.value = originalSetting.value;
2192 - jQuery( copySetting ).trigger( 'change' );
2193 - }
2194 - }
2195 -
2196 - function getKeyFromSettingInput( input ) {
2197 - var nameWithoutPrefix, nameSplit;
2198 - nameWithoutPrefix = input.name.substr( 14 );
2199 - nameSplit = nameWithoutPrefix.split( '_' );
2200 - nameSplit.pop();
2201 - return nameSplit.join( '_' );
2202 - }
2203 -
2204 - function closeOpenFieldDropdowns() {
2205 - var openSettings = document.querySelector( '.frm-field-settings-open' );
2206 - if ( null !== openSettings ) {
2207 - openSettings.classList.remove( 'frm-field-settings-open' );
2208 - jQuery( document ).off( 'click', '#frm_builder_page', handleClickOutsideOfFieldSettings );
2209 - jQuery( '.frm-field-action-icons .dropdown.open' ).removeClass( 'open' );
2210 - }
2211 - }
2212 -
2213 - function handleClickOutsideOfFieldSettings( event ) {
2214 - if ( ! jQuery( event.originalEvent.target ).closest( '.frm-field-action-icons' ).length ) {
2215 - closeOpenFieldDropdowns();
2216 - }
2217 - }
2218 -
2219 - function checkForMultiselectKeysOnMouseMove( event ) {
2220 - var keyIsDown = ! ! ( event.ctrlKey || event.metaKey || event.shiftKey );
2221 - jQuery( document.getElementById( 'frm_builder_page' ) ).toggleClass( 'frm-multiselect-key-is-down', keyIsDown );
2222 - checkForActiveHoverTarget( event );
2223 - }
2224 -
2225 - function checkForActiveHoverTarget( event ) {
2226 - var container, elementFromPoint, list, previousHoverTarget;
2227 -
2228 - container = postBodyContent;
2229 - if ( container.classList.contains( 'frm-dragging-field' ) ) {
2230 - return;
2231 - }
2232 -
2233 - if ( null !== document.querySelector( '.frm-field-group-hover-target .frm-field-settings-open' ) ) {
2234 - // do not set a hover target if a dropdown is open for the current hover target.
2235 - return;
2236 - }
2237 -
2238 - elementFromPoint = document.elementFromPoint( event.clientX, event.clientY );
2239 - if ( null !== elementFromPoint && ! elementFromPoint.classList.contains( 'edit_field_type_divider' ) ) {
2240 -
2241 - list = elementFromPoint.closest( 'ul.frm_sorting' );
2242 -
2243 - if ( null !== list && ! list.classList.contains( 'start_divider' ) && 'frm-show-fields' !== list.id ) {
2244 - previousHoverTarget = maybeRemoveGroupHoverTarget();
2245 - if ( false !== previousHoverTarget && ! jQuery( previousHoverTarget ).is( list ) ) {
2246 - destroyFieldGroupPopup();
2247 - }
2248 - updateFieldGroupControls( jQuery( list ), getFieldsInRow( jQuery( list ) ).length );
2249 - list.classList.add( 'frm-field-group-hover-target' );
2250 - jQuery( '#wpbody-content' ).on( 'mousemove', maybeRemoveHoverTargetOnMouseMove );
2251 - }
2252 - }
2253 - }
2254 -
2255 - function maybeRemoveGroupHoverTarget() {
2256 - var controls, previousHoverTarget;
2257 -
2258 - controls = document.getElementById( 'frm_field_group_controls' );
2259 - if ( null !== controls ) {
2260 - controls.style.display = 'none';
2261 - }
2262 -
2263 - previousHoverTarget = document.querySelector( '.frm-field-group-hover-target' );
2264 - if ( null === previousHoverTarget ) {
2265 - return false;
2266 - }
2267 -
2268 - jQuery( '#wpbody-content' ).off( 'mousemove', maybeRemoveHoverTargetOnMouseMove );
2269 - previousHoverTarget.classList.remove( 'frm-field-group-hover-target' );
2270 - return previousHoverTarget;
2271 - }
2272 -
2273 - function maybeRemoveHoverTargetOnMouseMove( event ) {
2274 - var elementFromPoint = document.elementFromPoint( event.clientX, event.clientY );
2275 - if ( null !== elementFromPoint && null !== elementFromPoint.closest( '#frm-show-fields' ) ) {
2276 - return;
2277 - }
2278 - maybeRemoveGroupHoverTarget();
2279 - }
2280 -
2281 - function onFieldActionDropdownShow( isFieldGroup ) {
2282 - unselectFieldGroups();
2283 - // maybe offset the dropdown if it goes off of the right of the screen.
2284 - setTimeout(
2285 - function() {
2286 - var ul, $ul;
2287 - ul = document.querySelector( '.dropdown.show .frm-dropdown-menu' );
2288 - if ( null === ul ) {
2289 - return;
2290 - }
2291 - if ( null === ul.getAttribute( 'aria-label' ) ) {
2292 - ul.setAttribute( 'aria-label', __( 'More Options', 'formidable' ) );
2293 - }
2294 - if ( 0 === ul.children.length ) {
2295 - fillFieldActionDropdown( ul, true === isFieldGroup );
2296 - }
2297 - $ul = jQuery( ul );
2298 - if ( $ul.offset().left > jQuery( window ).width() - $ul.outerWidth() ) {
2299 - ul.style.left = ( -$ul.outerWidth() ) + 'px';
2300 - }
2301 - const firstAnchor = ul.firstElementChild.querySelector( 'a' );
2302 - if ( firstAnchor ) {
2303 - firstAnchor.focus();
2304 - }
2305 - },
2306 - 0
2307 - );
2308 - }
2309 -
2310 - function onFieldGroupActionDropdownShow() {
2311 - onFieldActionDropdownShow( true );
2312 - }
2313 -
2314 - function changeSectionStyle( e ) {
2315 - const collapsedSection = e.target.closest( '.frm-section-collapsed' );
2316 - if ( ! collapsedSection ) {
2317 - return;
2318 - }
2319 -
2320 - if ( e.type === 'show' ) {
2321 - collapsedSection.style.zIndex = 3;
2322 - } else {
2323 - collapsedSection.style.zIndex = 1;
2324 - }
2325 - }
2326 -
2327 - function fillFieldActionDropdown( ul, isFieldGroup ) {
2328 - var classSuffix, options;
2329 - classSuffix = isFieldGroup ? '_field_group' : '_field';
2330 - options = [ getDeleteActionOption( isFieldGroup ), getDuplicateActionOption( isFieldGroup ) ];
2331 - if ( ! isFieldGroup ) {
2332 - options.push(
2333 - { class: 'frm_select', icon: 'frm_settings_icon', label: __( 'Field Settings', 'formidable' ) }
2334 - );
2335 - }
2336 - options.forEach(
2337 - function( option ) {
2338 - var li, anchor, span;
2339 - li = document.createElement( 'div' );
2340 - li.classList.add( 'frm_more_options_li', 'dropdown-item' );
2341 -
2342 - anchor = document.createElement( 'a' );
2343 - anchor.classList.add( option.class + classSuffix );
2344 - anchor.setAttribute( 'href', '#' );
2345 - makeTabbable( anchor );
2346 -
2347 - span = document.createElement( 'span' );
2348 - span.textContent = option.label;
2349 - anchor.innerHTML = '<svg class="frmsvg"><use xlink:href="#' + option.icon + '"></use></svg>';
2350 - anchor.appendChild( document.createTextNode( ' ' ) );
2351 - anchor.appendChild( span );
2352 -
2353 - li.appendChild( anchor );
2354 - ul.appendChild( li );
2355 - }
2356 - );
2357 - }
2358 -
2359 - function getDeleteActionOption( isFieldGroup ) {
2360 - var option = { class: 'frm_delete', icon: 'frm_delete_icon' };
2361 - option.label = isFieldGroup ? __( 'Delete Group', 'formidable' ) : __( 'Delete', 'formidable' );
2362 - return option;
2363 - }
2364 -
2365 - function getDuplicateActionOption( isFieldGroup ) {
2366 - var option = { class: 'frm_clone', icon: 'frm_clone_icon' };
2367 - option.label = isFieldGroup ? __( 'Duplicate Group', 'formidable' ) : __( 'Duplicate', 'formidable' );
2368 - return option;
2369 - }
2370 -
2371 - function wrapFieldLi( field ) {
2372 - const wrapper = div();
2373 -
2374 - if ( 'string' === typeof field ) {
2375 - wrapper.innerHTML = field;
2376 - } else {
2377 - wrapper.appendChild( field );
2378 - }
2379 -
2380 - let result = jQuery();
2381 - Array.from( wrapper.children ).forEach(
2382 - li => {
2383 - result = result.add(
2384 - jQuery( '<li>' )
2385 - .addClass( 'frm_field_box' )
2386 - .html(
2387 - jQuery( '<ul>' ).addClass( 'frm_grid_container frm_sorting' ).append( li )
2388 - )
2389 - );
2390 - }
2391 - );
2392 -
2393 - return result;
2394 - }
2395 -
2396 - function wrapFieldLiInPlace( li ) {
2397 - const ul = tag(
2398 - 'ul',
2399 - {
2400 - className: 'frm_grid_container frm_sorting'
2401 - }
2402 - );
2403 - const wrapper = tag(
2404 - 'li',
2405 - {
2406 - className: 'frm_field_box',
2407 - child: ul
2408 - }
2409 - );
2410 -
2411 - li.replaceWith( wrapper );
2412 - ul.appendChild( li );
2413 -
2414 - makeDroppable( ul );
2415 - makeDraggable( wrapper, '.frm-move' );
2416 - }
2417 -
2418 1268 function afterAddField( msg, addFocus ) {
2419 1269 var regex = /id="(\S+)"/,
2420 1270 match = regex.exec( msg ),
2421 1271 field = document.getElementById( match[1]),
2422 - section = '#' + match[1] + '.edit_field_type_divider ul.frm_sorting.start_divider',
1272 + section = '#' + match[1] + '.edit_field_type_divider ul.frm_sorting',
2423 1273 $thisSection = jQuery( section ),
2424 1274 type = field.getAttribute( 'data-type' ),
2425 - toggled = false,
2426 - $parentSection;
1275 + toggled = false;
2427 1276
2428 1277 setupSortable( section );
2429 1278
2430 1279 if ( 'quantity' === type ) {
@@ -2440,9 +1289,9 @@
2440 1289
2441 1290 if ( $thisSection.length ) {
2442 1291 $thisSection.parent( '.frm_field_box' ).children( '.frm_no_section_fields' ).addClass( 'frm_block' );
2443 1292 } else {
2444 - $parentSection = jQuery( field ).closest( 'ul.frm_sorting.start_divider' );
1293 + var $parentSection = jQuery( field ).closest( 'ul.frm_sorting' );
2445 1294 if ( $parentSection.length ) {
2446 1295 toggleOneSectionHolder( $parentSection );
2447 1296 toggled = true;
2448 1297 }
@@ -2480,28 +1329,18 @@
2480 1329 }
2481 1330
2482 1331 deselectFields();
2483 1332 initiateMultiselect();
2484 -
2485 - const addedEvent = new Event( 'frm_added_field', { bubbles: false });
2486 - addedEvent.frmField = field;
2487 - addedEvent.frmSection = section;
2488 - addedEvent.frmType = type;
2489 - addedEvent.frmToggles = toggled;
2490 - document.dispatchEvent( addedEvent );
2491 1333 }
2492 1334
2493 - function clearSettingsBox( preventFieldGroups ) {
1335 + function clearSettingsBox() {
2494 1336 jQuery( '#new_fields .frm-single-settings' ).addClass( 'frm_hidden' );
2495 1337 jQuery( '#frm-options-panel > .frm-single-settings' ).removeClass( 'frm_hidden' );
2496 - deselectFields( preventFieldGroups );
1338 + deselectFields();
2497 1339 }
2498 1340
2499 - function deselectFields( preventFieldGroups ) {
1341 + function deselectFields() {
2500 1342 jQuery( 'li.ui-state-default.selected' ).removeClass( 'selected' );
2501 - if ( ! preventFieldGroups ) {
2502 - unselectFieldGroups();
2503 - }
2504 1343 }
2505 1344
2506 1345 function scrollToField( field ) {
2507 1346 var newPos = field.getBoundingClientRect().top,
@@ -2531,13 +1370,13 @@
2531 1370 function checkDetailPageSlug() {
2532 1371 var slug = jQuery( '#param' ).val(),
2533 1372 msg;
2534 1373 slug = slug.trim().toLowerCase();
2535 - if ( Array.isArray( frm_admin_js.unsafe_params ) && frm_admin_js.unsafe_params.includes( slug ) ) { // eslint-disable-line camelcase
2536 - msg = frm_admin_js.slug_is_reserved; // eslint-disable-line camelcase
1374 + if ( Array.isArray( frm_admin_js.unsafe_params ) && frm_admin_js.unsafe_params.includes( slug ) ) {
1375 + msg = frm_admin_js.slug_is_reserved;
2537 1376 msg = msg.replace( '****', addHtmlTags( slug, 'strong' ) );
2538 1377 msg += '<br /><br />';
2539 - msg += addHtmlTags( '<a href="https://codex.wordpress.org/WordPress_Query_Vars" target="_blank" class="frm-standard-link">' + frm_admin_js.reserved_words + '</a>', 'div' ); // eslint-disable-line camelcase
1378 + msg += addHtmlTags( '<a href="https://codex.wordpress.org/WordPress_Query_Vars" target="_blank" class="frm-standard-link">' + frm_admin_js.reserved_words + '</a>', 'div' );
2540 1379 infoModal( msg );
2541 1380 }
2542 1381 }
2543 1382
@@ -2550,9 +1389,9 @@
2550 1389 match = regEx.exec( filterValue ),
2551 1390 unsafeParams = '';
2552 1391
2553 1392 while ( match !== null ) {
2554 - if ( Array.isArray( frm_admin_js.unsafe_params ) && frm_admin_js.unsafe_params.includes( match[1]) ) { // eslint-disable-line camelcase
1393 + if ( Array.isArray( frm_admin_js.unsafe_params ) && frm_admin_js.unsafe_params.includes( match[1]) ) {
2555 1394 if ( unsafeParams !== '' ) {
2556 1395 unsafeParams += '", "' + match[ 1 ];
2557 1396 } else {
2558 1397 unsafeParams = match[ 1 ];
@@ -2561,12 +1400,12 @@
2561 1400 match = regEx.exec( filterValue );
2562 1401 }
2563 1402
2564 1403 if ( unsafeParams !== '' ) {
2565 - msg = frm_admin_js.param_is_reserved; // eslint-disable-line camelcase
1404 + msg = frm_admin_js.param_is_reserved;
2566 1405 msg = msg.replace( '****', addHtmlTags( unsafeParams, 'strong' ) );
2567 1406 msg += '<br /><br />';
2568 - msg += ' <a href="https://codex.wordpress.org/WordPress_Query_Vars" target="_blank" class="frm-standard-link">' + frm_admin_js.reserved_words + '</a>'; // eslint-disable-line camelcase
1407 + msg += ' <a href="https://codex.wordpress.org/WordPress_Query_Vars" target="_blank" class="frm-standard-link">' + frm_admin_js.reserved_words + '</a>';
2569 1408
2570 1409 infoModal( msg );
2571 1410 }
2572 1411 }
@@ -2609,9 +1448,9 @@
2609 1448 }
2610 1449 }
2611 1450
2612 1451 if ( stack.length > 0 || unmatchedClosing.length > 0 ) {
2613 - msg = frm_admin_js.unmatched_parens + '\n\n'; // eslint-disable-line camelcase
1452 + msg = frm_admin_js.unmatched_parens + '\n\n';
2614 1453 return msg;
2615 1454 }
2616 1455
2617 1456 return '';
@@ -2647,9 +1486,9 @@
2647 1486
2648 1487 var nonNumericShortcodes = getNonNumericShortcodes();
2649 1488
2650 1489 if ( nonNumericShortcodes.test( calculation ) ) {
2651 - msg = frm_admin_js.text_shortcodes + '\n\n'; // eslint-disable-line camelcase
1490 + msg = frm_admin_js.text_shortcodes + '\n\n';
2652 1491 }
2653 1492
2654 1493 return msg;
2655 1494 }
@@ -2680,9 +1519,9 @@
2680 1519 var nonFormShortcodes = getNonFormShortcodes(),
2681 1520 msg = '';
2682 1521
2683 1522 if ( nonFormShortcodes.test( formula ) ) {
2684 - msg += frm_admin_js.view_shortcodes + '\n\n'; // eslint-disable-line camelcase
1523 + msg += frm_admin_js.view_shortcodes + '\n\n';
2685 1524 }
2686 1525
2687 1526 return msg;
2688 1527 }
@@ -2954,10 +1793,8 @@
2954 1793 addBlankSelectOption( changes, newValue );
2955 1794 }
2956 1795 } else if ( att === 'class' ) {
2957 1796 changeFieldClass( changes, this );
2958 - } else if ( isSliderField( changes ) ) {
2959 - updateSliderFieldPreview( changes, att, newValue );
2960 1797 } else {
2961 1798 changes.setAttribute( att, newValue );
2962 1799 }
2963 1800 } else if ( changes.id.indexOf( 'setup-message' ) === 0 ) {
@@ -2965,83 +1802,22 @@
2965 1802 changes.innerHTML = '<input type="text" value="" disabled />';
2966 1803 }
2967 1804 } else {
2968 1805 changes.innerHTML = newValue;
2969 -
2970 - if ( 'TEXTAREA' === changes.nodeName && changes.classList.contains( 'wp-editor-area' ) ) {
2971 - // Trigger change events on wysiwyg textareas so we can also sync default values in the visual tab.
2972 - jQuery( changes ).trigger( 'change' );
2973 - }
2974 -
2975 - if ( changes.classList.contains( 'frm_primary_label' ) && 'break' === changes.nextElementSibling.getAttribute( 'data-ftype' ) ) {
2976 - changes.nextElementSibling.querySelector( '.frm_button_submit' ).textContent = newValue;
2977 - }
2978 1806 }
2979 1807 }
2980 1808
2981 - function updateSliderFieldPreview( field, att, newValue ) {
2982 - if ( frmGlobal.proIncludesSliderJs ) {
2983 - const hookName = 'frm_update_slider_field_preview';
2984 - const hookArgs = { field, att, newValue };
2985 - wp.hooks.doAction( hookName, hookArgs );
2986 - return;
2987 - }
2988 -
2989 - // This functionality has been moved to pro since v5.4.3. This code should be removed eventually.
2990 - if ( 'value' === att ) {
2991 - if ( '' === newValue ) {
2992 - newValue = getSliderMidpoint( field );
2993 - }
2994 - field.value = newValue;
2995 - } else {
2996 - field.setAttribute( att, newValue );
2997 - }
2998 -
2999 - if ( -1 === [ 'value', 'min', 'max' ].indexOf( att ) ) {
3000 - return;
3001 - }
3002 -
3003 - if ( ( 'max' === att || 'min' === att ) && '' === getSliderDefaultValueInput( field.id ) ) {
3004 - field.value = getSliderMidpoint( field );
3005 - }
3006 -
3007 - field.parentNode.querySelector( '.frm_range_value' ).textContent = field.value;
3008 - }
3009 -
3010 - function getSliderDefaultValueInput( previewInputId ) {
3011 - return document.querySelector( 'input[data-changeme="' + previewInputId + '"][data-changeatt="value"]' ).value;
3012 - }
3013 -
3014 - function getSliderMidpoint( sliderInput ) {
3015 - const max = parseFloat( sliderInput.getAttribute( 'max' ) );
3016 - const min = parseFloat( sliderInput.getAttribute( 'min' ) );
3017 - return ( max - min ) / 2 + min;
3018 - }
3019 -
3020 - function isSliderField( previewInput ) {
3021 - return 'range' === previewInput.type && previewInput.parentNode.classList.contains( 'frm_range_container' );
3022 - }
3023 -
3024 1809 function toggleInvalidMsg() {
3025 1810 /*jshint validthis:true */
3026 1811 var typeDropdown, fieldType,
3027 - fieldId = this.getAttribute( 'data-fid' ),
3028 - value = '';
1812 + fieldId = this.id.replace( 'frm_format_', '' ),
1813 + hasValue = this.value !== '';
3029 1814
3030 - [ 'field_options_max_', 'frm_format_' ].forEach( function( id ) {
3031 - var input = document.getElementById( id + fieldId );
3032 - if ( ! input ) {
3033 - return;
3034 - }
3035 -
3036 - value += input.value;
3037 - });
3038 -
3039 1815 typeDropdown = document.getElementsByName( 'field_options[type_' + fieldId + ']' )[0];
3040 1816 fieldType = typeDropdown.options[typeDropdown.selectedIndex].value;
3041 1817
3042 1818 if ( fieldType === 'text' ) {
3043 - toggleValidationBox( '' !== value, '.frm_invalid_msg' + fieldId );
1819 + toggleValidationBox( hasValue, '.frm_invalid_msg' + fieldId );
3044 1820 }
3045 1821 }
3046 1822
3047 1823 function markRequired() {
@@ -3084,9 +1860,9 @@
3084 1860 if ( this.checked ) {
3085 1861 $thisField.fadeIn( 'fast' ).closest( '.frm_validation_msg' ).fadeIn( 'fast' );
3086 1862 $unqDetail = jQuery( '.frm_unique_details' + fieldId + ' input' );
3087 1863 if ( $unqDetail.val() === '' ) {
3088 - $unqDetail.val( frm_admin_js.default_unique ); // eslint-disable-line camelcase
1864 + $unqDetail.val( frm_admin_js.default_unique );
3089 1865 }
3090 1866 } else {
3091 1867 var v = $thisField.fadeOut( 'fast' ).closest( '.frm_validation_box' ).children( ':not(.frm_unique_details' + fieldId + '):visible' ).length;
3092 1868 if ( v === 0 ) {
@@ -3107,9 +1883,9 @@
3107 1883 if ( val !== '' ) {
3108 1884 //Add default validation message if empty
3109 1885 var valMsg = jQuery( '.frm_validation_box .frm_conf_details' + fieldId + ' input' );
3110 1886 if ( valMsg.val() === '' ) {
3111 - valMsg.val( frm_admin_js.default_conf ); // eslint-disable-line camelcase
1887 + valMsg.val( frm_admin_js.default_conf );
3112 1888 }
3113 1889
3114 1890 setConfirmationFieldDescriptions( fieldId );
3115 1891
@@ -3132,19 +1908,19 @@
3132 1908 var fieldType = document.getElementsByName( 'field_options[type_' + fieldId + ']' )[0].value;
3133 1909
3134 1910 var fieldDescription = document.getElementById( 'field_description_' + fieldId );
3135 1911 var hiddenDescName = 'field_options[description_' + fieldId + ']';
3136 - var newValue = frm_admin_js['enter_' + fieldType]; // eslint-disable-line camelcase
1912 + var newValue = frm_admin_js['enter_' + fieldType];
3137 1913 maybeSetNewDescription( fieldDescription, hiddenDescName, newValue );
3138 1914
3139 1915 var confFieldDescription = document.getElementById( 'conf_field_description_' + fieldId );
3140 1916 var hiddenConfName = 'field_options[conf_desc_' + fieldId + ']';
3141 - var newConfValue = frm_admin_js['confirm_' + fieldType]; // eslint-disable-line camelcase
1917 + var newConfValue = frm_admin_js['confirm_' + fieldType];
3142 1918 maybeSetNewDescription( confFieldDescription, hiddenConfName, newConfValue );
3143 1919 }
3144 1920
3145 1921 function maybeSetNewDescription( descriptionDiv, hiddenName, newValue ) {
3146 - if ( descriptionDiv.innerHTML === frm_admin_js.desc ) { // eslint-disable-line camelcase
1922 + if ( descriptionDiv.innerHTML === frm_admin_js.desc ) {
3147 1923
3148 1924 // Set the visible description value and the hidden description value
3149 1925 descriptionDiv.innerHTML = newValue;
3150 1926 document.getElementsByName( hiddenName )[0].value = newValue;
@@ -3163,21 +1939,14 @@
3163 1939 jQuery( builderForm ).on( 'click', 'a.frm-bulk-edit-link', function( event ) {
3164 1940 event.preventDefault();
3165 1941 var i, key, label,
3166 1942 content = '',
3167 - optList,
3168 - opts,
3169 1943 fieldId = jQuery( this ).closest( '[data-fid]' ).data( 'fid' ),
3170 1944 separate = usingSeparateValues( fieldId ),
1945 + optList = document.getElementById( 'frm_field_' + fieldId + '_opts' ),
1946 + opts = optList.getElementsByTagName( 'li' ),
3171 1947 product = isProductField( fieldId );
3172 1948
3173 - optList = document.getElementById( 'frm_field_' + fieldId + '_opts' );
3174 - if ( ! optList ) {
3175 - return;
3176 - }
3177 -
3178 - opts = optList.getElementsByTagName( 'li' );
3179 -
3180 1949 document.getElementById( 'bulk-field-id' ).value = fieldId;
3181 1950
3182 1951 for ( i = 0; i < opts.length; i++ ) {
3183 1952 key = opts[i].getAttribute( 'data-optkey' );
@@ -3205,16 +1974,9 @@
3205 1974 return false;
3206 1975 });
3207 1976
3208 1977 jQuery( '#frm-update-bulk-opts' ).on( 'click', function() {
3209 - var fieldId = document.getElementById( 'bulk-field-id' ).value;
3210 - var optionType = document.getElementById( 'bulk-option-type' ).value;
3211 -
3212 - if ( optionType ) {
3213 - // Use custom handler for custom option type.
3214 - return;
3215 - }
3216 -
1978 + var fieldId = document.getElementById( 'bulk-field-id' ).value;
3217 1979 this.classList.add( 'frm_loading_button' );
3218 1980 frmAdminBuild.updateOpts( fieldId, document.getElementById( 'frm_bulk_options' ).value, $info );
3219 1981 });
3220 1982 }
@@ -3267,11 +2029,9 @@
3267 2029 newOption = newOption.replace( new RegExp( '-' + oldKey + '_', 'g' ), '-' + optKey + '_' );
3268 2030 newOption = newOption.replace( new RegExp( '-' + oldKey + '"', 'g' ), '-' + optKey + '"' );
3269 2031 newOption = newOption.replace( new RegExp( '\\[' + oldKey + '\\]', 'g' ), '[' + optKey + ']' );
3270 2032 newOption = newOption.replace( 'frm_hidden frm_option_template', '' );
3271 - newOption = { newOption };
3272 - addSaveAndDragIconsToOption( fieldId, newOption );
3273 - jQuery( document.getElementById( 'frm_field_' + fieldId + '_opts' ) ).append( newOption.newOption );
2033 + jQuery( document.getElementById( 'frm_field_' + fieldId + '_opts' ) ).append( newOption );
3274 2034 resetDisplayedOpts( fieldId );
3275 2035 }
3276 2036 }
3277 2037
@@ -3386,15 +2146,20 @@
3386 2146 refreshOptionDisplayNow( jQuery( this ) );
3387 2147 }
3388 2148
3389 2149 function addImageToOption( event ) {
3390 - const imagePreview = event.target.closest( '.frm_image_preview_wrapper' );
2150 + var fileFrame,
2151 + $this = jQuery( this ),
2152 + $field = $this.closest( '.frm-single-settings' ),
2153 + $imagePreview = $this.closest( '.frm_image_preview_wrapper' ),
2154 + fieldId = $field.data( 'fid' ),
2155 + postID = 0;
3391 2156
3392 2157 event.preventDefault();
3393 2158
3394 - wp.media.model.settings.post.id = 0;
2159 + wp.media.model.settings.post.id = postID;
3395 2160
3396 - const fileFrame = wp.media.frames.file_frame = wp.media({
2161 + fileFrame = wp.media.frames.file_frame = wp.media({
3397 2162 multiple: false,
3398 2163 library: {
3399 2164 type: [ 'image' ]
3400 2165 }
@@ -3401,22 +2166,15 @@
3401 2166 });
3402 2167
3403 2168 fileFrame.on( 'select', function() {
3404 2169 const attachment = fileFrame.state().get( 'selection' ).first().toJSON();
3405 - const img = imagePreview.querySelector( 'img' );
3406 -
3407 - img.setAttribute( 'src', attachment.url );
3408 - img.classList.remove( 'frm_hidden' );
3409 - img.removeAttribute( 'srcset' ); // Prevent the old image from sticking around.
3410 -
3411 - imagePreview.querySelector( '.frm_image_preview_frame' ).style.display = 'block';
3412 - imagePreview.querySelector( '.frm_image_preview_title' ).textContent = attachment.filename;
3413 - imagePreview.querySelector( '.frm_choose_image_box' ).style.display = 'none';
3414 -
3415 - const $imagePreview = jQuery( imagePreview );
2170 + $imagePreview.find( 'img' ).attr( 'src', attachment.url );
2171 + $imagePreview.find( '.frm_image_preview_frame' ).show();
2172 + $imagePreview.find( '.frm_image_preview_title' ).text( attachment.filename );
3416 2173 $imagePreview.siblings( 'input[name*="[label]"]' ).data( 'frmimgurl', attachment.url );
2174 + $imagePreview.find( '.frm_choose_image_box' ).hide();
3417 2175 $imagePreview.find( 'input.frm_image_id' ).val( attachment.id ).trigger( 'change' );
3418 - wp.media.model.settings.post.id = 0;
2176 + wp.media.model.settings.post.id = postID;
3419 2177 });
3420 2178
3421 2179 fileFrame.open();
3422 2180 }
@@ -3422,8 +2180,10 @@
3422 2180 }
3423 2181
3424 2182 function removeImageFromOption( event ) {
3425 2183 var $this = jQuery( this ),
2184 + $field = $this.closest( '.frm-single-settings' ),
2185 + fieldId = $field.data( 'fid' ),
3426 2186 previewWrapper = $this.closest( '.frm_image_preview_wrapper' );
3427 2187
3428 2188 event.preventDefault();
3429 2189 event.stopPropagation();
@@ -3456,26 +2216,8 @@
3456 2216 }
3457 2217 }
3458 2218
3459 2219 /**
3460 - * Dismiss a warning message and send an AJAX request to update the dismissal state.
3461 - *
3462 - * @since 6.3
3463 - *
3464 - * @param {Event} event The event object associated with the click on the dismiss icon.
3465 - */
3466 - function dismissWarningMessage( event ) {
3467 - const target = event.target;
3468 -
3469 - const warningEl = target.closest( '.frm_warning_style' );
3470 - jQuery( warningEl ).fadeOut( 400, () => warningEl.remove() );
3471 -
3472 - const action = target.dataset.action;
3473 - const formData = new FormData();
3474 - doJsonPost( action, formData );
3475 - }
3476 -
3477 - /**
3478 2220 * If a field is clicked in the builder, prevent inputs from changing.
3479 2221 */
3480 2222 function stopFieldFocus( e ) {
3481 2223 e.preventDefault();
@@ -3533,41 +2275,22 @@
3533 2275 * If the field option has the default text, clear it out on click.
3534 2276 */
3535 2277 function maybeClearOptText() {
3536 2278 /*jshint validthis:true */
3537 - if ( this.value === frm_admin_js.new_option ) { // eslint-disable-line camelcase
2279 + if ( this.value === frm_admin_js.new_option ) {
3538 2280 this.setAttribute( 'data-value-on-focus', this.value );
3539 2281 this.value = '';
3540 2282 }
3541 2283 }
3542 2284
3543 - function confirmFieldsDeleteMessage( numberOfFields ) {
3544 - /* translators: %1$s: Number of fields that are selected to be deleted. */
3545 - return __( 'Are you sure you want to delete these %1$s selected field(s)?', 'formidable' ).replace( '%1$s', numberOfFields );
3546 - }
3547 -
3548 2285 function clickDeleteField() {
3549 2286 /*jshint validthis:true */
3550 - var confirmMsg = frm_admin_js.conf_delete, // eslint-disable-line camelcase
3551 - maybeDivider = this.parentNode.parentNode.parentNode.parentNode.parentNode,
2287 + var confirmMsg = frm_admin_js.conf_delete,
2288 + maybeDivider = this.parentNode.parentNode.parentNode,
3552 2289 li = maybeDivider.parentNode,
3553 - field = jQuery( this ).closest( 'li.form-field' ),
2290 + field = jQuery( this ).closest( 'li' ),
3554 2291 fieldId = field.data( 'fid' );
3555 2292
3556 - if ( field.data( 'ftype' ) === 'divider' ) {
3557 - const fieldBoxes = document.querySelectorAll( '.frm-field-group-hover-target .start_divider .frm_field_box' );
3558 - let fieldIdsToDelete = 0;
3559 - fieldBoxes.forEach( fieldBox => {
3560 - const fieldsInsideFieldBox = fieldBox.querySelectorAll( 'li.form-field' );
3561 - if ( fieldsInsideFieldBox ) {
3562 - fieldIdsToDelete += fieldsInsideFieldBox.length;
3563 - }
3564 - });
3565 - if ( fieldIdsToDelete ) {
3566 - confirmMsg = confirmFieldsDeleteMessage( ++fieldIdsToDelete );
3567 - }
3568 - }
3569 -
3570 2293 if ( li.classList.contains( 'frm-section-collapsed' ) || li.classList.contains( 'frm-page-collapsed' ) ) {
3571 2294 return false;
3572 2295 }
3573 2296
@@ -3572,969 +2295,19 @@
3572 2295 }
3573 2296
3574 2297 // If deleting a section, use a special message.
3575 2298 if ( maybeDivider.className === 'divider_section_only' ) {
3576 - confirmMsg = frm_admin_js.conf_delete_sec; // eslint-disable-line camelcase
2299 + confirmMsg = frm_admin_js.conf_delete_sec;
2300 + this.setAttribute( 'data-frmcaution', frm_admin_js.caution );
3577 2301 }
3578 2302
3579 2303 this.setAttribute( 'data-frmverify', confirmMsg );
3580 - this.setAttribute( 'data-frmverify-btn', 'frm-button-red' );
3581 2304 this.setAttribute( 'data-deletefield', fieldId );
3582 2305
3583 - closeOpenFieldDropdowns();
3584 -
3585 2306 confirmLinkClick( this );
3586 2307 return false;
3587 2308 }
3588 2309
3589 - function clickSelectField() {
3590 - this.closest( 'li.form-field' ).click();
3591 - }
3592 -
3593 - function clickDeleteFieldGroup() {
3594 - var hoverTarget, decoy;
3595 -
3596 - hoverTarget = document.querySelector( '.frm-field-group-hover-target' );
3597 - if ( null === hoverTarget ) {
3598 - return;
3599 - }
3600 -
3601 - hoverTarget.classList.add( 'frm-selected-field-group' );
3602 -
3603 - decoy = document.createElement( 'div' );
3604 - decoy.classList.add( 'frm-delete-field-groups', 'frm_hidden' );
3605 - document.body.appendChild( decoy );
3606 - decoy.click();
3607 - }
3608 -
3609 - function duplicateFieldGroup() {
3610 - const hoverTarget = document.querySelector( '.frm-field-group-hover-target' );
3611 - if ( null === hoverTarget ) {
3612 - return;
3613 - }
3614 -
3615 - const newRowId = 'frm_field_group_' + getAutoId();
3616 - const placeholderUlChild = document.createTextNode( '' );
3617 - wrapFieldLiInPlace( placeholderUlChild );
3618 -
3619 - const newRow = jQuery( placeholderUlChild ).closest( 'li' ).get( 0 );
3620 - newRow.classList.add( 'frm_hidden' );
3621 -
3622 - const newRowUl = newRow.querySelector( 'ul' );
3623 - newRowUl.id = newRowId;
3624 -
3625 - jQuery( hoverTarget.closest( 'li.frm_field_box' ) ).after( newRow );
3626 -
3627 - const $fields = getFieldsInRow( jQuery( hoverTarget ) );
3628 - const syncDetails = [];
3629 - const injectedCloneOptions = [];
3630 -
3631 - const expectedLength = $fields.length;
3632 - const originalFieldIdByDuplicatedFieldId = {};
3633 -
3634 - let duplicatedCount = 0;
3635 -
3636 - jQuery( newRow ).on(
3637 - 'frm_added_duplicated_field_to_row',
3638 - function( _, args ) {
3639 - originalFieldIdByDuplicatedFieldId[ jQuery( args.duplicatedFieldHtml ).attr( 'data-fid' ) ] = args.originalFieldId;
3640 -
3641 - if ( expectedLength > ++duplicatedCount ) {
3642 - return;
3643 - }
3644 -
3645 - const $newRowUl = jQuery( newRowUl );
3646 - const $duplicatedFields = getFieldsInRow( $newRowUl );
3647 -
3648 - injectedCloneOptions.forEach(
3649 - function( cloneOption ) {
3650 - cloneOption.remove();
3651 - }
3652 - );
3653 -
3654 - for ( let index = 0; index < expectedLength; ++index ) {
3655 - $newRowUl.append( $newRowUl.children( 'li.form-field[frm-field-order="' + index + '"]' ) );
3656 - }
3657 -
3658 - syncLayoutClasses( $duplicatedFields.first(), syncDetails );
3659 - newRow.classList.remove( 'frm_hidden' );
3660 - updateFieldOrder();
3661 -
3662 - getFieldsInRow( $newRowUl ).each(
3663 - function() {
3664 - maybeDuplicateUnsavedSettings( originalFieldIdByDuplicatedFieldId[ this.getAttribute( 'data-fid' ) ], jQuery( this ).prop( 'outerHTML' ) );
3665 - }
3666 - );
3667 - }
3668 - );
3669 -
3670 - $fields.each(
3671 - function( index ) {
3672 - var cloneOption;
3673 - cloneOption = document.createElement( 'li' );
3674 - cloneOption.classList.add( 'frm_clone_field' );
3675 - cloneOption.setAttribute( 'frm-target-row-id', newRowId );
3676 - cloneOption.setAttribute( 'frm-field-order', index );
3677 - this.appendChild( cloneOption );
3678 - cloneOption.click();
3679 - injectedCloneOptions.push( cloneOption );
3680 - syncDetails.push( getSizeOfLayoutClass( getLayoutClassName( this.classList ) ) );
3681 - }
3682 - );
3683 - }
3684 -
3685 - function clickFieldGroupLayout() {
3686 - var hoverTarget, sizeOfFieldGroup, popupWrapper;
3687 -
3688 - hoverTarget = document.querySelector( '.frm-field-group-hover-target' );
3689 -
3690 - if ( null === hoverTarget ) {
3691 - return;
3692 - }
3693 -
3694 - deselectFields();
3695 -
3696 - sizeOfFieldGroup = getSizeOfFieldGroupFromChildElement( hoverTarget.querySelector( 'li.form-field' ) );
3697 -
3698 - hoverTarget.classList.add( 'frm-has-open-field-group-popup' );
3699 - jQuery( document ).on( 'click', '#frm_builder_page', destroyFieldGroupPopupOnOutsideClick );
3700 -
3701 - popupWrapper = div();
3702 - popupWrapper.style.position = 'relative';
3703 - popupWrapper.appendChild( getFieldGroupPopup( sizeOfFieldGroup, this ) );
3704 - this.parentNode.appendChild( popupWrapper );
3705 -
3706 - const firstLayoutOption = popupWrapper.querySelector( '.frm-row-layout-option' );
3707 - if ( firstLayoutOption ) {
3708 - firstLayoutOption.focus();
3709 - }
3710 - }
3711 -
3712 - function destroyFieldGroupPopupOnOutsideClick( event ) {
3713 - if ( event.target.classList.contains( 'frm-custom-field-group-layout' ) || event.target.classList.contains( 'frm-cancel-custom-field-group-layout' ) ) {
3714 - return;
3715 - }
3716 - if ( ! jQuery( event.target ).closest( '#frm_field_group_controls' ).length && ! jQuery( event.target ).closest( '#frm_field_group_popup' ).length ) {
3717 - destroyFieldGroupPopup();
3718 - }
3719 - }
3720 -
3721 - function getSizeOfFieldGroupFromChildElement( element ) {
3722 - var $ul = jQuery( element ).closest( 'ul' );
3723 - if ( $ul.length ) {
3724 - return getFieldsInRow( $ul ).length;
3725 - }
3726 - return getSelectedFieldCount();
3727 - }
3728 -
3729 - function getFieldGroupPopup( sizeOfFieldGroup, childElement ) {
3730 - var popup, wrapper, rowLayoutOptions, ul;
3731 -
3732 - popup = document.getElementById( 'frm_field_group_popup' );
3733 - if ( null === popup ) {
3734 - popup = div();
3735 - } else {
3736 - popup.innerHTML = '';
3737 - }
3738 -
3739 - popup.id = 'frm_field_group_popup';
3740 -
3741 - wrapper = div();
3742 - wrapper.style.padding = '0 24px 12px';
3743 - wrapper.appendChild( getRowLayoutTitle() );
3744 -
3745 - rowLayoutOptions = getRowLayoutOptions( sizeOfFieldGroup );
3746 -
3747 - ul = childElement.closest( 'ul.frm_sorting' );
3748 - if ( null !== ul ) {
3749 - maybeMarkRowLayoutAsActive( ul, rowLayoutOptions );
3750 - }
3751 -
3752 - wrapper.appendChild( rowLayoutOptions );
3753 -
3754 - popup.appendChild( wrapper );
3755 - popup.appendChild( separator() );
3756 -
3757 - popup.appendChild( getCustomLayoutOption() );
3758 - popup.appendChild( getBreakIntoDifferentRowsOption() );
3759 -
3760 - return popup;
3761 - }
3762 -
3763 - function maybeMarkRowLayoutAsActive( activeRow, options ) {
3764 - var length, index, currentRow;
3765 -
3766 - length = options.children.length;
3767 - for ( index = 0; index < length; ++index ) {
3768 - currentRow = options.children[ index ];
3769 - if ( rowLayoutsMatch( currentRow, activeRow ) ) {
3770 - currentRow.classList.add( 'frm-active-row-layout' );
3771 - return;
3772 - }
3773 - }
3774 - }
3775 -
3776 - function separator() {
3777 - var hr = document.createElement( 'hr' );
3778 - return hr;
3779 - }
3780 -
3781 - function getCustomLayoutOption() {
3782 - var option = div();
3783 - option.textContent = __( 'Custom layout', 'formidable' );
3784 - jQuery( option ).prepend( getIconClone( 'frm_gear_svg' ) );
3785 - option.classList.add( 'frm-custom-field-group-layout' );
3786 - makeTabbable( option );
3787 - return option;
3788 - }
3789 -
3790 - function makeTabbable( element, ariaLabel ) {
3791 - element.setAttribute( 'tabindex', 0 );
3792 - element.setAttribute( 'role', 'button' );
3793 - if ( 'undefined' !== typeof ariaLabel ) {
3794 - element.setAttribute( 'aria-label', ariaLabel );
3795 - }
3796 - }
3797 -
3798 - function getIconClone( iconId ) {
3799 - var clone = document.getElementById( iconId ).cloneNode( true );
3800 - clone.id = '';
3801 - return clone;
3802 - }
3803 -
3804 - function getBreakIntoDifferentRowsOption() {
3805 - var option = div();
3806 - option.textContent = __( 'Break into rows', 'formidable' );
3807 - jQuery( option ).prepend( getIconClone( 'frm_break_field_group_svg' ) );
3808 - option.classList.add( 'frm-break-field-group' );
3809 - makeTabbable( option );
3810 - return option;
3811 - }
3812 -
3813 - function getRowLayoutTitle() {
3814 - var rowLayoutTitle = div();
3815 - rowLayoutTitle.classList.add( 'frm-row-layout-title' );
3816 - rowLayoutTitle.textContent = __( 'Row Layout', 'formidable' );
3817 - return rowLayoutTitle;
3818 - }
3819 -
3820 - function getRowLayoutOptions( size ) {
3821 - var wrapper, padding;
3822 -
3823 - wrapper = getEmptyGridContainer();
3824 - if ( 5 !== size ) {
3825 - wrapper.appendChild( getRowLayoutOption( size, 'even' ) );
3826 - }
3827 - if ( size % 2 === 1 ) {
3828 - // only include the middle option for odd numbers because even doesn't make a lot of sense.
3829 - wrapper.appendChild( getRowLayoutOption( size, 'middle' ) );
3830 - }
3831 - if ( size < 6 ) {
3832 - wrapper.appendChild( getRowLayoutOption( size, 'left' ) );
3833 - wrapper.appendChild( getRowLayoutOption( size, 'right' ) );
3834 - } else {
3835 - padding = div();
3836 - padding.classList.add( 'frm_fourth' );
3837 - wrapper.prepend( padding );
3838 - }
3839 -
3840 - return wrapper;
3841 - }
3842 -
3843 - function getRowLayoutOption( size, type ) {
3844 - var option, useClass;
3845 -
3846 - option = div();
3847 - option.classList.add( 'frm-row-layout-option' );
3848 - makeTabbable( option, type );
3849 -
3850 - switch ( size ) {
3851 - case 6:
3852 - useClass = 'frm_half';
3853 - break;
3854 - case 5:
3855 - useClass = 'frm_third';
3856 - break;
3857 - default:
3858 - useClass = size % 2 === 1 ? 'frm_fourth' : 'frm_third';
3859 - break;
3860 - }
3861 -
3862 - option.classList.add( useClass );
3863 - option.setAttribute( 'layout-type', type );
3864 -
3865 - option.appendChild( getRowForSizeAndType( size, type ) );
3866 - return option;
3867 - }
3868 -
3869 - function rowLayoutsMatch( row1, row2 ) {
3870 - return getRowLayoutAsKey( row1 ) === getRowLayoutAsKey( row2 );
3871 - }
3872 -
3873 - function getRowLayoutAsKey( row ) {
3874 - var $fields, sizes;
3875 - if ( row.classList.contains( 'frm-row-layout-option' ) ) {
3876 - $fields = jQuery( row ).find( '.frm_grid_container' ).children();
3877 - } else {
3878 - $fields = getFieldsInRow( jQuery( row ) );
3879 - }
3880 - sizes = [];
3881 - $fields.each(
3882 - function() {
3883 - sizes.push( getSizeOfLayoutClass( getLayoutClassName( this.classList ) ) );
3884 - }
3885 - );
3886 - return sizes.join( '-' );
3887 - }
3888 -
3889 - function getRowForSizeAndType( size, type ) {
3890 - var row, index, block;
3891 -
3892 - row = getEmptyGridContainer();
3893 - for ( index = 0; index < size; ++index ) {
3894 - block = div();
3895 - block.classList.add( getClassForBlock( size, type, index ) );
3896 - block.style.height = '16px';
3897 - block.style.background = '#9EA9B8';
3898 - block.style.borderRadius = '1px';
3899 - row.appendChild( block );
3900 - }
3901 -
3902 - return row;
3903 - }
3904 -
3905 - /**
3906 - * @param {int} size 2-6.
3907 - * @param {string} type even, middle, left, or right.
3908 - * @param {int} index 0-5.
3909 - * @returns string
3910 - */
3911 - function getClassForBlock( size, type, index ) {
3912 - if ( 'even' === type ) {
3913 - return getEvenClassForSize( size, index );
3914 - } else if ( 'middle' === type ) {
3915 - if ( 3 === size ) {
3916 - return 1 === index ? 'frm6' : 'frm3';
3917 - }
3918 - if ( 5 === size ) {
3919 - return 2 === index ? 'frm4' : 'frm2';
3920 - }
3921 - } else if ( 'left' === type ) {
3922 - return 0 === index ? getLargeClassForSize( size ) : getSmallClassForSize( size );
3923 - } else if ( 'right' === type ) {
3924 - return index === size - 1 ? getLargeClassForSize( size ) : getSmallClassForSize( size );
3925 - }
3926 - return 'frm12';
3927 - }
3928 -
3929 - function getEvenClassForSize( size, index ) {
3930 - if ( -1 !== [ 2, 3, 4, 6 ].indexOf( size ) ) {
3931 - return getLayoutClassForSize( 12 / size );
3932 - }
3933 - if ( 5 === size && 'undefined' !== typeof index ) {
3934 - return 0 === index ? 'frm4' : 'frm2';
3935 - }
3936 - return 'frm12';
3937 - }
3938 -
3939 - function getSmallClassForSize( size ) {
3940 - switch ( size ) {
3941 - case 2: case 3:
3942 - return 'frm3';
3943 - case 4:
3944 - return 'frm2';
3945 - case 5:
3946 - return 'frm2';
3947 - case 6:
3948 - return 'frm1';
3949 - }
3950 - return 'frm12';
3951 - }
3952 -
3953 - function getLargeClassForSize( size ) {
3954 - switch ( size ) {
3955 - case 2:
3956 - return 'frm9';
3957 - case 3: case 4:
3958 - return 'frm6';
3959 - case 5:
3960 - return 'frm4';
3961 - case 6:
3962 - return 'frm7';
3963 - }
3964 - return 'frm12';
3965 - }
3966 -
3967 - function getEmptyGridContainer() {
3968 - var wrapper = div();
3969 - wrapper.classList.add( 'frm_grid_container' );
3970 - return wrapper;
3971 - }
3972 -
3973 - /**
3974 - * Handle when a field group layout option (that sets grid classes/column sizing) is selected in the "Row Layout" popup.
3975 - *
3976 - * @returns {void}
3977 - */
3978 - function handleFieldGroupLayoutOptionClick() {
3979 - const row = document.querySelector( '.frm-field-group-hover-target' );
3980 - if ( ! row ) {
3981 - // The field group layout options also get clicked when merging multiple rows.
3982 - // The following code isn't required for multiple rows though so just exit early.
3983 - return;
3984 - }
3985 -
3986 - const type = this.getAttribute( 'layout-type' );
3987 - syncLayoutClasses( getFieldsInRow( jQuery( row ) ).first(), type );
3988 - destroyFieldGroupPopup();
3989 - }
3990 -
3991 - function handleFieldGroupLayoutOptionInsideMergeClick() {
3992 - var $ul, type;
3993 - $ul = mergeSelectedFieldGroups();
3994 - type = this.getAttribute( 'layout-type' );
3995 - syncLayoutClasses( getFieldsInRow( $ul ).first(), type );
3996 - unselectFieldGroups();
3997 - }
3998 -
3999 - function mergeSelectedFieldGroups() {
4000 - var $selectedFieldGroups = jQuery( '.frm-selected-field-group' ),
4001 - $firstGroupUl = $selectedFieldGroups.first();
4002 - $selectedFieldGroups.not( $firstGroupUl ).each(
4003 - function() {
4004 - getFieldsInRow( jQuery( this ) ).each(
4005 - function() {
4006 - var previousParent = this.parentNode;
4007 - getFieldsInRow( $firstGroupUl ).last().after( this );
4008 - if ( ! jQuery( previousParent ).children( 'li.form-field' ).length ) {
4009 - // clean up the previous field group if we've removed all of its fields.
4010 - previousParent.closest( 'li.frm_field_box' ).remove();
4011 - }
4012 - }
4013 - );
4014 - }
4015 - );
4016 - updateFieldOrder();
4017 - syncLayoutClasses( getFieldsInRow( $firstGroupUl ).first() );
4018 - return $firstGroupUl;
4019 - }
4020 -
4021 - function customFieldGroupLayoutClick() {
4022 - var $fields;
4023 - if ( null !== this.closest( '.frm-merge-fields-into-row' ) ) {
4024 - return;
4025 - }
4026 - $fields = getFieldsInRow( jQuery( '.frm-field-group-hover-target' ) );
4027 - setupCustomLayoutOptions( $fields );
4028 - }
4029 -
4030 - function setupCustomLayoutOptions( $fields ) {
4031 - var size, popup, wrapper, layoutClass, inputRow, paddingElement, inputValueOverride, index, inputField, heading, label, buttonsWrapper, cancelButton, saveButton;
4032 -
4033 - size = $fields.length;
4034 -
4035 - popup = document.getElementById( 'frm_field_group_popup' );
4036 - popup.innerHTML = '';
4037 -
4038 - wrapper = div();
4039 - wrapper.style.padding = '24px';
4040 -
4041 - layoutClass = getEvenClassForSize( 5 === size ? 6 : size );
4042 -
4043 - inputRow = div();
4044 - inputRow.style.padding = '20px 0';
4045 - inputRow.classList.add( 'frm_grid_container' );
4046 -
4047 - if ( 5 === size ) {
4048 - // add a span to pad the inputs by 1 column, to account for the missing 2 columns.
4049 - paddingElement = document.createElement( 'span' );
4050 - paddingElement.classList.add( 'frm1' );
4051 - inputRow.appendChild( paddingElement );
4052 - }
4053 -
4054 - inputValueOverride = getSelectedFieldCount() > 0 ? getSizeOfLayoutClass( getEvenClassForSize( size ) ) : false;
4055 - if ( false !== inputValueOverride && inputValueOverride >= 12 ) {
4056 - inputValueOverride = Math.floor( 12 / size );
4057 - }
4058 -
4059 - for ( index = 0; index < size; ++index ) {
4060 - inputField = document.createElement( 'input' );
4061 - inputField.type = 'text';
4062 - inputField.classList.add( layoutClass );
4063 - inputField.classList.add( 'frm-custom-grid-size-input' );
4064 - inputField.value = false !== inputValueOverride ? inputValueOverride : getSizeOfLayoutClass( getLayoutClassName( $fields.get( index ).classList ) );
4065 - inputRow.appendChild( inputField );
4066 - }
4067 -
4068 - heading = div();
4069 - heading.classList.add( 'frm-builder-popup-heading' );
4070 - heading.textContent = __( 'Enter number of columns for each field', 'formidable' );
4071 -
4072 - label = div();
4073 - label.classList.add( 'frm-builder-popup-subheading' );
4074 - label.textContent = __( 'Layouts are based on a 12-column grid system', 'formidable' );
4075 -
4076 - wrapper.appendChild( heading );
4077 - wrapper.appendChild( label );
4078 -
4079 - wrapper.appendChild( inputRow );
4080 -
4081 - buttonsWrapper = div();
4082 - buttonsWrapper.style.textAlign = 'right';
4083 -
4084 - cancelButton = getSecondaryButton();
4085 - cancelButton.textContent = __( 'Cancel', 'formidable' );
4086 - cancelButton.classList.add( 'frm-cancel-custom-field-group-layout' );
4087 - cancelButton.style.marginRight = '10px';
4088 -
4089 - saveButton = getPrimaryButton();
4090 - saveButton.textContent = __( 'Save', 'formidable' );
4091 - saveButton.classList.add( 'frm-save-custom-field-group-layout' );
4092 -
4093 - buttonsWrapper.appendChild( cancelButton );
4094 - buttonsWrapper.appendChild( saveButton );
4095 -
4096 - wrapper.appendChild( buttonsWrapper );
4097 -
4098 - popup.appendChild( wrapper );
4099 -
4100 - setTimeout(
4101 - function() {
4102 - const firstInput = popup.querySelector( 'input.frm-custom-grid-size-input' ).focus();
4103 - if ( firstInput ) {
4104 - firstInput.focus();
4105 - }
4106 - },
4107 - 0
4108 - );
4109 - }
4110 -
4111 - function customFieldGroupLayoutInsideMergeClick() {
4112 - $fields = jQuery( '.frm-selected-field-group li.form-field' );
4113 - setupCustomLayoutOptions( $fields );
4114 - }
4115 -
4116 - function getPrimaryButton() {
4117 - var button = getButton();
4118 - button.classList.add( 'button-primary', 'frm-button-primary' );
4119 - return button;
4120 - }
4121 -
4122 - function getSecondaryButton() {
4123 - var button = getButton();
4124 - button.classList.add( 'button-secondary', 'frm-button-secondary' );
4125 - return button;
4126 - }
4127 -
4128 - function getButton() {
4129 - var button = document.createElement( 'a' );
4130 - button.setAttribute( 'href', '#' );
4131 - button.classList.add( 'button' );
4132 - button.style.textDecoration = 'none';
4133 - return button;
4134 - }
4135 -
4136 - function getSizeOfLayoutClass( className ) {
4137 - switch ( className ) {
4138 - case 'frm_half':
4139 - return 6;
4140 - case 'frm_third':
4141 - return 4;
4142 - case 'frm_two_thirds':
4143 - return 8;
4144 - case 'frm_fourth':
4145 - return 3;
4146 - case 'frm_three_fourths':
4147 - return 9;
4148 - case 'frm_sixth':
4149 - return 2;
4150 - }
4151 -
4152 - if ( 0 === className.indexOf( 'frm' ) ) {
4153 - return parseInt( className.substr( 3 ) );
4154 - }
4155 -
4156 - // Anything missing a layout class should be a full width row.
4157 - return 12;
4158 - }
4159 -
4160 - function getLayoutClassName( classList ) {
4161 - var classes, index, currentClass;
4162 - classes = getLayoutClasses();
4163 - for ( index = 0; index < classes.length; ++index ) {
4164 - currentClass = classes[ index ];
4165 - if ( classList.contains( currentClass ) ) {
4166 - return currentClass;
4167 - }
4168 - }
4169 - return '';
4170 - }
4171 -
4172 - function getLayoutClassForSize( size ) {
4173 - return 'frm' + size;
4174 - }
4175 -
4176 - function breakFieldGroupClick() {
4177 - var row = document.querySelector( '.frm-field-group-hover-target' );
4178 - breakRow( row );
4179 - destroyFieldGroupPopup();
4180 - }
4181 -
4182 - function breakRow( row ) {
4183 - const $row = jQuery( row );
4184 - getFieldsInRow( $row ).each(
4185 - function( index ) {
4186 - const field = this;
4187 - if ( 0 !== index ) {
4188 - $row.parent().after( wrapFieldLi( field ) );
4189 - }
4190 - stripLayoutFromFields( jQuery( field ) );
4191 - }
4192 - );
4193 - }
4194 -
4195 - function stripLayoutFromFields( field ) {
4196 - syncLayoutClasses( field, 'clear' );
4197 - }
4198 -
4199 - function focusFieldGroupInputOnClick() {
4200 - this.select();
4201 - }
4202 -
4203 - function cancelCustomFieldGroupClick() {
4204 - revertToFieldGroupPopupFirstPage( this );
4205 - }
4206 -
4207 - function revertToFieldGroupPopupFirstPage( triggerElement ) {
4208 - jQuery( document.getElementById( 'frm_field_group_popup' ) ).replaceWith(
4209 - getFieldGroupPopup( getSizeOfFieldGroupFromChildElement( triggerElement ), triggerElement )
4210 - );
4211 - }
4212 -
4213 - function destroyFieldGroupPopup() {
4214 - var popup, wrapper;
4215 - popup = document.getElementById( 'frm_field_group_popup' );
4216 - if ( popup === null ) {
4217 - return;
4218 - }
4219 - wrapper = document.querySelector( '.frm-has-open-field-group-popup' );
4220 - if ( null !== wrapper ) {
4221 - wrapper.classList.remove( 'frm-has-open-field-group-popup' );
4222 - popup.parentNode.remove();
4223 - }
4224 - jQuery( document ).off( 'click', '#frm_builder_page', destroyFieldGroupPopupOnOutsideClick );
4225 - }
4226 -
4227 - function saveCustomFieldGroupClick() {
4228 - var syncDetails, $controls, $ul;
4229 -
4230 - syncDetails = [];
4231 -
4232 - jQuery( document.getElementById( 'frm_field_group_popup' ).querySelectorAll( '.frm_grid_container input' ) )
4233 - .each(
4234 - function() {
4235 - syncDetails.push( parseInt( this.value ) );
4236 - }
4237 - );
4238 -
4239 - $controls = jQuery( document.getElementById( 'frm_field_group_controls' ) );
4240 -
4241 - if ( $controls.length && 'none' !== $controls.get( 0 ).style.display ) {
4242 - syncLayoutClasses( getFieldsInRow( jQuery( document.querySelector( '.frm-field-group-hover-target' ) ) ).first(), syncDetails );
4243 - } else {
4244 - $ul = mergeSelectedFieldGroups();
4245 - syncLayoutClasses( getFieldsInRow( $ul ).first(), syncDetails );
4246 - unselectFieldGroups();
4247 - }
4248 -
4249 - destroyFieldGroupPopup();
4250 - }
4251 -
4252 - function fieldGroupClick( e ) {
4253 - if ( 'ul' !== e.originalEvent.target.nodeName.toLowerCase() ) {
4254 - // only continue if the group itself was clicked / ignore when a field is clicked.
4255 - return;
4256 - }
4257 -
4258 - const hoverTarget = document.querySelector( '.frm-field-group-hover-target' );
4259 - if ( ! hoverTarget ) {
4260 - return;
4261 - }
4262 -
4263 - const ctrlOrCmdKeyIsDown = e.ctrlKey || e.metaKey;
4264 - const shiftKeyIsDown = e.shiftKey;
4265 - const groupIsActive = hoverTarget.classList.contains( 'frm-selected-field-group' );
4266 - const $selectedFieldGroups = getSelectedFieldGroups();
4267 -
4268 - let numberOfSelectedGroups = $selectedFieldGroups.length;
4269 -
4270 - if ( ctrlOrCmdKeyIsDown || shiftKeyIsDown ) {
4271 - // multi-selecting
4272 -
4273 - const selectedField = getSelectedField();
4274 - if ( null !== selectedField && ! jQuery( selectedField ).siblings( 'li.form-field' ).length ) {
4275 - // count a selected field on its own as a selected field group when multiselecting.
4276 - selectedField.parentNode.classList.add( 'frm-selected-field-group' );
4277 - ++numberOfSelectedGroups;
4278 - }
4279 -
4280 - if ( ctrlOrCmdKeyIsDown ) {
4281 - if ( groupIsActive ) {
4282 - // unselect if holding ctrl or cmd and the group was already active.
4283 - --numberOfSelectedGroups;
4284 - hoverTarget.classList.remove( 'frm-selected-field-group' );
4285 - syncAfterMultiSelect( numberOfSelectedGroups );
4286 - return; // exit early to avoid adding back frm-selected-field-group
4287 - } else {
4288 - ++numberOfSelectedGroups;
4289 - }
4290 - } else if ( shiftKeyIsDown && ! groupIsActive ) {
4291 - ++numberOfSelectedGroups; // include the one we're selecting right now.
4292 - const $firstGroup = $selectedFieldGroups.first();
4293 -
4294 - let $range;
4295 - if ( $firstGroup.parent().index() < jQuery( hoverTarget.parentNode ).index() ) {
4296 - $range = $firstGroup.parent().nextUntil( hoverTarget.parentNode );
4297 - } else {
4298 - $range = $firstGroup.parent().prevUntil( hoverTarget.parentNode );
4299 - }
4300 -
4301 - $range.each(
4302 - function() {
4303 - var $fieldGroup = jQuery( this ).closest( 'li' ).find( 'ul.frm_sorting' );
4304 - if ( ! $fieldGroup.hasClass( 'frm-selected-field-group' ) ) {
4305 - ++numberOfSelectedGroups;
4306 - $fieldGroup.addClass( 'frm-selected-field-group' );
4307 - }
4308 - }
4309 - );
4310 -
4311 - // when holding shift and clicking, text gets selected. unselect it.
4312 - document.getSelection().removeAllRanges();
4313 - }
4314 - } else {
4315 - // not multi-selecting
4316 - unselectFieldGroups();
4317 - numberOfSelectedGroups = 1;
4318 - }
4319 -
4320 - hoverTarget.classList.add( 'frm-selected-field-group' );
4321 - syncAfterMultiSelect( numberOfSelectedGroups );
4322 -
4323 - jQuery( document ).off( 'click', unselectFieldGroups );
4324 - jQuery( document ).on( 'click', unselectFieldGroups );
4325 - }
4326 -
4327 - function getSelectedField() {
4328 - return document.getElementById( 'frm-show-fields' ).querySelector( 'li.form-field.selected' );
4329 - }
4330 -
4331 - function getSelectedFieldGroups() {
4332 - const $fieldGroups = jQuery( '.frm-selected-field-group' );
4333 - if ( $fieldGroups.length ) {
4334 - return $fieldGroups;
4335 - }
4336 -
4337 - const selectedField = getSelectedField();
4338 - if ( selectedField ) {
4339 - // If there is only one field in a group and the field is selected, consider the field's group as selected for multi-select.
4340 - const selectedFieldGroup = selectedField.closest( 'ul' );
4341 - if ( selectedFieldGroup && 1 === getFieldsInRow( jQuery( selectedFieldGroup ) ).length ) {
4342 - selectedFieldGroup.classList.add( 'frm-selected-field-group' );
4343 - return jQuery( selectedFieldGroup );
4344 - }
4345 - }
4346 -
4347 - return jQuery();
4348 - }
4349 -
4350 - function syncAfterMultiSelect( numberOfSelectedGroups ) {
4351 - clearSettingsBox( true ); // unselect any fields if one is selected.
4352 - if ( numberOfSelectedGroups >= 2 || ( 1 === numberOfSelectedGroups && selectedGroupHasMultipleFields() ) ) {
4353 - addFieldMultiselectPopup();
4354 - } else {
4355 - maybeRemoveMultiselectPopup();
4356 - }
4357 - maybeRemoveGroupHoverTarget();
4358 - }
4359 -
4360 - function selectedGroupHasMultipleFields() {
4361 - return getFieldsInRow( jQuery( document.querySelector( '.frm-selected-field-group' ) ) ).length > 1;
4362 - }
4363 -
4364 - function unselectFieldGroups( event ) {
4365 - if ( 'undefined' !== typeof event ) {
4366 - if ( null !== event.originalEvent.target.closest( '#frm-show-fields' ) ) {
4367 - return;
4368 - }
4369 - if ( event.originalEvent.target.classList.contains( 'frm-merge-fields-into-row' ) ) {
4370 - return;
4371 - }
4372 - if ( null !== event.originalEvent.target.closest( '.frm-merge-fields-into-row' ) ) {
4373 - return;
4374 - }
4375 - if ( event.originalEvent.target.classList.contains( 'frm-custom-field-group-layout' ) ) {
4376 - return;
4377 - }
4378 - if ( event.originalEvent.target.classList.contains( 'frm-cancel-custom-field-group-layout' ) ) {
4379 - return;
4380 - }
4381 - }
4382 - jQuery( '.frm-selected-field-group' ).removeClass( 'frm-selected-field-group' );
4383 - jQuery( document ).off( 'click', unselectFieldGroups );
4384 - maybeRemoveMultiselectPopup();
4385 - }
4386 -
4387 - function maybeRemoveMultiselectPopup() {
4388 - var popup = document.getElementById( 'frm_field_multiselect_popup' );
4389 - if ( null !== popup ) {
4390 - popup.remove();
4391 - }
4392 - }
4393 -
4394 - function addFieldMultiselectPopup() {
4395 - getFieldMultiselectPopup();
4396 - }
4397 -
4398 - function getFieldMultiselectPopup() {
4399 - var popup, mergeOption, caret, verticalSeparator, deleteOption;
4400 -
4401 - popup = document.getElementById( 'frm_field_multiselect_popup' );
4402 -
4403 - if ( null !== popup ) {
4404 - popup.classList.toggle( 'frm-unmergable', ! selectedFieldsAreMergable() );
4405 - return popup;
4406 - }
4407 -
4408 - popup = div();
4409 - popup.id = 'frm_field_multiselect_popup';
4410 - if ( ! selectedFieldsAreMergable() ) {
4411 - popup.classList.add( 'frm-unmergable' );
4412 - }
4413 -
4414 - mergeOption = div();
4415 - mergeOption.classList.add( 'frm-merge-fields-into-row' );
4416 - mergeOption.textContent = __( 'Merge into row', 'formidable' );
4417 -
4418 - caret = document.createElement( 'a' );
4419 - caret.style.marginLeft = '5px';
4420 - caret.classList.add( 'frm_icon_font', 'frm_arrowdown6_icon' );
4421 - caret.setAttribute( 'href', '#' );
4422 - mergeOption.appendChild( caret );
4423 -
4424 - popup.appendChild( mergeOption );
4425 -
4426 - verticalSeparator = div();
4427 - verticalSeparator.classList.add( 'frm-multiselect-popup-separator' );
4428 - popup.appendChild( verticalSeparator );
4429 -
4430 - deleteOption = div();
4431 - deleteOption.classList.add( 'frm-delete-field-groups' );
4432 - deleteOption.appendChild( getIconClone( 'frm_trash_svg' ) );
4433 - popup.appendChild( deleteOption );
4434 -
4435 - document.getElementById( 'post-body-content' ).appendChild( popup );
4436 -
4437 - jQuery( popup ).hide().fadeIn();
4438 -
4439 - return popup;
4440 - }
4441 -
4442 - function selectedFieldsAreMergable() {
4443 - var selectedFieldGroups, totalFieldCount, length, index, fieldGroup;
4444 - selectedFieldGroups = document.querySelectorAll( '.frm-selected-field-group' );
4445 - length = selectedFieldGroups.length;
4446 - if ( 1 === length ) {
4447 - return false;
4448 - }
4449 - totalFieldCount = 0;
4450 - for ( index = 0; index < length; ++index ) {
4451 - fieldGroup = selectedFieldGroups[ index ];
4452 - if ( null !== fieldGroup.querySelector( '.edit_field_type_break, .edit_field_type_hidden' ) ) {
4453 - return false;
4454 - }
4455 - totalFieldCount += getFieldsInRow( jQuery( fieldGroup ) ).length;
4456 - if ( totalFieldCount > 6 ) {
4457 - return false;
4458 - }
4459 - }
4460 - return true;
4461 - }
4462 -
4463 - function mergeFieldsIntoRowClick( event ) {
4464 - var size, popup;
4465 -
4466 - if ( null !== event.originalEvent.target.closest( '#frm_field_group_popup' ) ) {
4467 - // prevent clicks within the popup from triggering the button again.
4468 - return;
4469 - }
4470 -
4471 - if ( event.originalEvent.target.classList.contains( 'frm-custom-field-group-layout' ) ) {
4472 - // avoid switching back to the first page when clicking the custom option nested inside of the merge option.
4473 - return;
4474 - }
4475 -
4476 - size = getSelectedFieldCount();
4477 - popup = getFieldGroupPopup( size, document.querySelector( '.frm-selected-field-group' ).firstChild );
4478 - this.appendChild( popup );
4479 - }
4480 -
4481 - function getSelectedFieldCount() {
4482 - var count = 0;
4483 - jQuery( document.querySelectorAll( '.frm-selected-field-group' ) ).each(
4484 - function() {
4485 - count += getFieldsInRow( jQuery( this ) ).length;
4486 - }
4487 - );
4488 - return count;
4489 - }
4490 -
4491 - function deleteFieldGroupsClick() {
4492 - var fieldIdsToDelete, deleteOnConfirm, multiselectPopup;
4493 -
4494 - fieldIdsToDelete = getSelectedFieldIds();
4495 - deleteOnConfirm = getDeleteSelectedFieldGroupsOnConfirmFunction( fieldIdsToDelete );
4496 -
4497 - multiselectPopup = document.getElementById( 'frm_field_multiselect_popup' );
4498 - if ( null !== multiselectPopup ) {
4499 - multiselectPopup.remove();
4500 - }
4501 -
4502 - this.setAttribute( 'data-frmverify', confirmFieldsDeleteMessage( fieldIdsToDelete.length ) );
4503 - confirmLinkClick( this );
4504 -
4505 - jQuery( '#frm-confirmed-click' ).on( 'click', deleteOnConfirm );
4506 - jQuery( '#frm_confirm_modal' ).one( 'dialogclose', function() {
4507 - jQuery( '#frm-confirmed-click' ).off( 'click', deleteOnConfirm );
4508 - });
4509 - }
4510 -
4511 - function getSelectedFieldIds() {
4512 - var deleteFieldIds = [];
4513 - jQuery( '.frm-selected-field-group > li.form-field' )
4514 - .each(
4515 - function() {
4516 - deleteFieldIds.push( this.dataset.fid );
4517 - }
4518 - );
4519 - return deleteFieldIds;
4520 - }
4521 -
4522 - function getDeleteSelectedFieldGroupsOnConfirmFunction( deleteFieldIds ) {
4523 - return function( event ) {
4524 - event.preventDefault();
4525 - deleteAllSelectedFieldGroups( deleteFieldIds );
4526 - };
4527 - }
4528 -
4529 - function deleteAllSelectedFieldGroups( deleteFieldIds ) {
4530 - deleteFieldIds.forEach(
4531 - function( fieldId ) {
4532 - deleteFields( fieldId );
4533 - }
4534 - );
4535 - }
4536 -
4537 2310 function deleteFieldConfirmed() {
4538 2311 /*jshint validthis:true */
4539 2312 deleteFields( this.getAttribute( 'data-deletefield' ) );
4540 2313 }
@@ -4575,24 +2348,16 @@
4575 2348 settings.remove();
4576 2349
4577 2350 $thisField.fadeOut( 'slow', function() {
4578 2351 var $section = $thisField.closest( '.start_divider' ),
4579 - type = $thisField.data( 'type' ),
4580 - $adjacentFields = $thisField.siblings( 'li.form-field' ),
4581 - $liWrapper;
4582 -
4583 - if ( ! $adjacentFields.length ) {
4584 - if ( $thisField.is( '.edit_field_type_end_divider' ) ) {
4585 - $adjacentFields.length = $thisField.closest( 'li.form-field' ).siblings();
4586 - } else {
4587 - $liWrapper = $thisField.closest( 'ul.frm_sorting' ).parent();
4588 - }
4589 - }
4590 -
2352 + type = $thisField.data( 'type' );
4591 2353 $thisField.remove();
4592 2354 if ( type === 'break' ) {
4593 2355 renumberPageBreaks();
4594 2356 }
2357 + if ( type === 'summary' ) {
2358 + reenableAddSummaryBtn();
2359 + }
4595 2360 if ( type === 'product' ) {
4596 2361 maybeHideQuantityProductFieldOption();
4597 2362 // a product field attached to a quantity field earlier might be the one deleted, so re-populate
4598 2363 popAllProductFields();
@@ -4601,16 +2366,8 @@
4601 2366 document.getElementById( 'frm_form_editor_container' ).classList.remove( 'frm-has-fields' );
4602 2367 } else if ( $section.length ) {
4603 2368 toggleOneSectionHolder( $section );
4604 2369 }
4605 - if ( $adjacentFields.length ) {
4606 - syncLayoutClasses( $adjacentFields.first() );
4607 - } else {
4608 - $liWrapper.remove();
4609 - }
4610 -
4611 - // prevent "More Options" tooltips from staying around after their target field is deleted.
4612 - deleteTooltips();
4613 2370 });
4614 2371 }
4615 2372 });
4616 2373 }
@@ -4725,9 +2482,9 @@
4725 2482 return;
4726 2483 }
4727 2484 }
4728 2485
4729 - if ( '' !== this.value || frm_admin_js.new_option !== this.getAttribute( 'data-value-on-focus' ) ) { // eslint-disable-line camelcase
2486 + if ( '' !== this.value || frm_admin_js.new_option !== this.getAttribute( 'data-value-on-focus' ) ) {
4730 2487 this.setAttribute( 'data-value-on-focus', this.value );
4731 2488 }
4732 2489 }
4733 2490
@@ -4851,25 +2608,21 @@
4851 2608 /*jshint validthis:true */
4852 2609 var link, lookupBlock,
4853 2610 fieldID = this.name.replace( 'field_options[data_type_', '' ).replace( ']', '' );
4854 2611
4855 - link = document.getElementById( 'frm_add_watch_lookup_link_' + fieldID ).parentNode;
4856 -
4857 2612 if ( this.value === 'text' ) {
4858 2613 lookupBlock = document.getElementById( 'frm_watch_lookup_block_' + fieldID );
4859 2614 if ( lookupBlock !== null ) {
4860 - // Clear and hide the Watch Fields option
2615 + // Clear the Watch Fields option
4861 2616 lookupBlock.innerHTML = '';
4862 - link.classList.add( 'frm_hidden' );
4863 2617
4864 2618 // Hide the Watch Fields row
2619 + link = document.getElementById( 'frm_add_watch_lookup_link_' + fieldID ).parentNode;
2620 + link.style.display = 'none';
4865 2621 link.previousElementSibling.style.display = 'none';
4866 2622 link.previousElementSibling.previousElementSibling.style.display = 'none';
4867 2623 link.previousElementSibling.previousElementSibling.previousElementSibling.style.display = 'none';
4868 2624 }
4869 - } else {
4870 - // Show the Watch Fields option
4871 - link.classList.remove( 'frm_hidden' );
4872 2625 }
4873 2626
4874 2627 toggleMultiSelect( fieldID, this.value );
4875 2628 }
@@ -4888,9 +2641,9 @@
4888 2641 containerClass.add( 'frm-first-page' );
4889 2642 } else {
4890 2643 containerClass.remove( 'frm-first-page' );
4891 2644 }
4892 - pages[i].textContent = ( i + 1 );
2645 + pages[i].innerHTML = ( i + 1 );
4893 2646 }
4894 2647 } else {
4895 2648 document.getElementById( 'frm-fake-page' ).style.display = 'none';
4896 2649 }
@@ -4908,9 +2661,9 @@
4908 2661 }
4909 2662
4910 2663 // Find all fields in a page and hide/show them
4911 2664 function toggleCollapsePage( field ) {
4912 - var toCollapse = getAllFieldsForPage( field.get( 0 ).parentNode.closest( 'li.frm_field_box' ).nextElementSibling );
2665 + var toCollapse = field.nextUntil( '.frm_field_box[data-ftype=break]' );
4913 2666 togglePage( field, toCollapse );
4914 2667 }
4915 2668
4916 2669 function toggleCollapseFakePage() {
@@ -4915,9 +2668,9 @@
4915 2668
4916 2669 function toggleCollapseFakePage() {
4917 2670 var topLevel = document.getElementById( 'frm-fake-page' ),
4918 2671 firstField = document.getElementById( 'frm-show-fields' ).firstElementChild,
4919 - toCollapse = getAllFieldsForPage( firstField );
2672 + toCollapse = jQuery( firstField ).add( jQuery( firstField ).nextUntil( '.frm_field_box[data-ftype=break]' ) );
4920 2673
4921 2674 if ( firstField.getAttribute( 'data-ftype' ) === 'break' ) {
4922 2675 // Don't collapse if the first field is a page break.
4923 2676 return;
@@ -4925,30 +2678,8 @@
4925 2678
4926 2679 togglePage( jQuery( topLevel ), toCollapse );
4927 2680 }
4928 2681
4929 - function getAllFieldsForPage( firstWrapper ) {
4930 - var $fieldsForPage, currentWrapper;
4931 -
4932 - $fieldsForPage = jQuery();
4933 -
4934 - if ( null === firstWrapper ) {
4935 - return $fieldsForPage;
4936 - }
4937 -
4938 - currentWrapper = firstWrapper;
4939 -
4940 - do {
4941 - if ( null !== currentWrapper.querySelector( '.edit_field_type_break' ) ) {
4942 - break;
4943 - }
4944 - $fieldsForPage = $fieldsForPage.add( jQuery( currentWrapper ) );
4945 - currentWrapper = currentWrapper.nextElementSibling;
4946 - } while ( null !== currentWrapper );
4947 -
4948 - return $fieldsForPage;
4949 - }
4950 -
4951 2682 function togglePage( field, toCollapse ) {
4952 2683 var i,
4953 2684 fieldCount = toCollapse.length,
4954 2685 slide = Math.min( fieldCount, 3 );
@@ -5054,13 +2785,10 @@
5054 2785 }
5055 2786
5056 2787 function clickVis( e ) {
5057 2788 /*jshint validthis:true */
5058 - var currentClass, originalList;
5059 -
5060 - currentClass = e.target.classList;
5061 -
5062 - if ( currentClass.contains( 'frm-collapse-page' ) || currentClass.contains( 'frm-sub-label' ) || e.target.closest( '.dropdown' ) !== null ) {
2789 + var currentClass = e.target.classList;
2790 + if ( currentClass.contains( 'frm-collapse-page' ) || currentClass.contains( 'frm-sub-label' ) ) {
5063 2791 return;
5064 2792 }
5065 2793
5066 2794 if ( this.closest( '.start_divider' ) !== null ) {
@@ -5065,19 +2793,8 @@
5065 2793
5066 2794 if ( this.closest( '.start_divider' ) !== null ) {
5067 2795 e.stopPropagation();
5068 2796 }
5069 -
5070 - if ( this.classList.contains( 'edit_field_type_divider' ) ) {
5071 - originalList = e.originalEvent.target.closest( 'ul.frm_sorting' );
5072 - if ( null !== originalList ) {
5073 - // prevent section click if clicking a field group within a section.
5074 - if ( originalList.classList.contains( 'edit_field_type_divider' ) || originalList.parentNode.parentNode.classList.contains( 'start_divider' ) ) {
5075 - return;
5076 - }
5077 - }
5078 - }
5079 -
5080 2797 clickAction( this );
5081 2798 }
5082 2799
5083 2800 /**
@@ -5104,9 +2821,9 @@
5104 2821 function checkRepeatLimit() {
5105 2822 /*jshint validthis:true */
5106 2823 var val = this.value;
5107 2824 if ( val !== '' && ( val < 2 || val > 200 ) ) {
5108 - infoModal( frm_admin_js.repeat_limit_min ); // eslint-disable-line camelcase
2825 + infoModal( frm_admin_js.repeat_limit_min );
5109 2826 this.value = '';
5110 2827 }
5111 2828 }
5112 2829
@@ -5113,9 +2830,9 @@
5113 2830 function checkCheckboxSelectionsLimit() {
5114 2831 /*jshint validthis:true */
5115 2832 var val = this.value;
5116 2833 if ( val !== '' && ( val < 1 || val > 200 ) ) {
5117 - infoModal( frm_admin_js.checkbox_limit ); // eslint-disable-line camelcase
2834 + infoModal( frm_admin_js.checkbox_limit );
5118 2835 this.value = '';
5119 2836 }
5120 2837 }
5121 2838
@@ -5152,31 +2869,19 @@
5152 2869 }
5153 2870
5154 2871 function resetOptOnChange() {
5155 2872 /*jshint validthis:true */
5156 - var field, thisOpt;
2873 + var field = getFieldKeyFromOpt( this ),
2874 + thisOpt = jQuery( this ).closest( '.frm_single_option' );
5157 2875
5158 - field = getFieldKeyFromOpt( this );
5159 - if ( ! field ) {
5160 - return;
5161 - }
5162 -
5163 - thisOpt = jQuery( this ).closest( '.frm_single_option' );
5164 -
5165 2876 resetSingleOpt( field.fieldId, field.fieldKey, thisOpt );
5166 2877 }
5167 2878
5168 2879 function getFieldKeyFromOpt( object ) {
5169 - var allOpts, fieldId, fieldKey;
2880 + var allOpts = jQuery( object ).closest( '.frm_sortable_field_opts' ),
2881 + fieldId = allOpts.attr( 'id' ).replace( 'frm_field_', '' ).replace( '_opts', '' ),
2882 + fieldKey = allOpts.data( 'key' );
5170 2883
5171 - allOpts = jQuery( object ).closest( '.frm_sortable_field_opts' );
5172 - if ( ! allOpts.length ) {
5173 - return false;
5174 - }
5175 -
5176 - fieldId = allOpts.attr( 'id' ).replace( 'frm_field_', '' ).replace( '_opts', '' );
5177 - fieldKey = allOpts.data( 'key' );
5178 -
5179 2884 return {
5180 2885 fieldId: fieldId,
5181 2886 fieldKey: fieldKey
5182 2887 };
@@ -5230,29 +2935,9 @@
5230 2935 text[ text.length - 1 ].nodeValue = '';
5231 2936 single.append( labelForDisplay );
5232 2937 }
5233 2938 } else {
5234 - let firstInputIndex = false;
5235 - text.forEach( ( node, index ) => {
5236 - if ( firstInputIndex === false ) {
5237 - if ( node.tagName === 'INPUT' ) {
5238 - firstInputIndex = index;
5239 - }
5240 - } else {
5241 - if ( index === firstInputIndex + 1 ) {
5242 - let nodeValue = '';
5243 -
5244 - if ( buttonsAsOptions( fieldId ) ) {
5245 - nodeValue = div({ className: 'frm_label_button_container', text: ' ' + label.val() });
5246 - single[0].replaceChild( nodeValue, node );
5247 - } else {
5248 - node.nodeValue = ' ' + label.val();
5249 - }
5250 - } else {
5251 - single[0].removeChild( node );
5252 - }
5253 - }
5254 - });
2939 + text[ text.length - 1 ].nodeValue = ' ' + label.val();
5255 2940 }
5256 2941
5257 2942 // Set saved value.
5258 2943 previewInput.val( saved );
@@ -5261,15 +2946,8 @@
5261 2946 defaultVal = thisOpt.find( 'input[name^="default_value_"]' );
5262 2947 previewInput.prop( 'checked', defaultVal.is( ':checked' ) ? true : false );
5263 2948 }
5264 2949
5265 - function buttonsAsOptions( fieldId ) {
5266 - const fields = document.getElementsByName( 'field_options[image_options_' + fieldId + ']' );
5267 - const result = Array.from( fields ).find( field => field.checked && ( 'buttons' === field.value ) );
5268 -
5269 - return typeof result !== 'undefined';
5270 - }
5271 -
5272 2950 /**
5273 2951 * Set the displayed value for an image option.
5274 2952 */
5275 2953 function getImageDisplayValue( thisOpt, fieldId, label ) {
@@ -5396,17 +3074,17 @@
5396 3074
5397 3075 function addRadioCheckboxOpt( type, opt, fieldId, fieldKey, isProduct, classes ) {
5398 3076 var other, single,
5399 3077 isOther = opt.key.indexOf( 'other' ) !== -1,
5400 - id = 'field_' + fieldKey + '-' + opt.key,
5401 - inputType = type === 'scale' ? 'radio' : type;
5402 3078
3079 + id = 'field_' + fieldKey + '-' + opt.key;
3080 +
5403 3081 other = '<input type="text" id="field_' + fieldKey + '-' + opt.key + '-otext" class="frm_other_input frm_pos_none" name="item_meta[other][' + fieldId + '][' + opt.key + ']" value="" />';
5404 3082
5405 3083 single = '<div class="frm_' + type + ' ' + type + ' ' + classes + '" id="frm_' + type + '_' + fieldId + '-' + opt.key + '"><label for="' + id +
5406 - '"><input type="' + inputType +
3084 + '"><input type="' + type +
5407 3085 '" name="item_meta[' + fieldId + ']' + ( type === 'checkbox' ? '[]' : '' ) +
5408 - '" value="' + purifyHtml( opt.saved ) + '" id="' + id + '"' + ( isProduct ? ' data-price="' + opt.price + '"' : '' ) + ( opt.checked ? ' checked="checked"' : '' ) + '> ' + purifyHtml( opt.label ) + '</label>' +
3086 + '" value="' + opt.saved + '" id="' + id + '"' + ( isProduct ? ' data-price="' + opt.price + '"' : '' ) + ( opt.checked ? ' checked="checked"' : '' ) + '> ' + opt.label + '</label>' +
5409 3087 ( isOther ? other : '' ) +
5410 3088 '</div>';
5411 3089
5412 3090 return single;
@@ -5438,9 +3116,9 @@
5438 3116
5439 3117 if ( ! isOther || showOther ) {
5440 3118 var opt = document.createElement( 'option' );
5441 3119 opt.value = opts[ i ].saved;
5442 - opt.innerHTML = purifyHtml( label );
3120 + opt.innerHTML = label;
5443 3121
5444 3122 if ( isProduct ) {
5445 3123 opt.setAttribute( 'data-price', opts[ i ].price );
5446 3124 }
@@ -5464,25 +3142,24 @@
5464 3142 }
5465 3143 }
5466 3144
5467 3145 function getMultipleOpts( fieldId ) {
5468 - let i, saved, labelName, label, key, optObj,
5469 - fieldType,
3146 + var i, saved, labelName, label, key, optObj,
3147 + image, savedLabel, input, field, checkbox, fieldType,
5470 3148 checked = false,
5471 3149 opts = [],
5472 - imageUrl = '';
3150 + imageUrl = '',
5473 3151
5474 - const optVals = jQuery( 'input[name^="field_options[options_' + fieldId + ']"]' );
5475 - const isProduct = isProductField( fieldId );
5476 - const showLabelWithImage = showingLabelWithImage( fieldId );
5477 - const hasImageOptions = imagesAsOptions( fieldId );
5478 - const separateValues = usingSeparateValues( fieldId );
3152 + optVals = jQuery( 'input[name^="field_options[options_' + fieldId + ']"]' ),
3153 + separateValues = usingSeparateValues( fieldId ),
3154 + hasImageOptions = imagesAsOptions( fieldId ),
3155 + showLabelWithImage = showingLabelWithImage( fieldId ),
3156 + isProduct = isProductField( fieldId );
5479 3157
5480 3158 for ( i = 0; i < optVals.length; i++ ) {
5481 3159 if ( optVals[ i ].name.indexOf( '[000]' ) > 0 || optVals[ i ].name.indexOf( '[value]' ) > 0 || optVals[ i ].name.indexOf( '[image]' ) > 0 || optVals[ i ].name.indexOf( '[price]' ) > 0 ) {
5482 3160 continue;
5483 3161 }
5484 -
5485 3162 saved = optVals[ i ].value;
5486 3163 label = saved;
5487 3164 key = optVals[ i ].name.replace( 'field_options[options_' + fieldId + '][', '' ).replace( '[label]', '' ).replace( ']', '' );
5488 3165
@@ -5491,18 +3168,13 @@
5491 3168 saved = jQuery( 'input[name="' + labelName + '"]' ).val();
5492 3169 }
5493 3170
5494 3171 if ( hasImageOptions ) {
5495 - imageUrl = getImageUrlFromInput( optVals[i]);
3172 + imageUrl = getImageUrlFromInput( optVals[i]);
5496 3173 fieldType = radioOrCheckbox( fieldId );
5497 - label = getImageLabel( label, showLabelWithImage, imageUrl, fieldType );
3174 + label = getImageLabel( label, showLabelWithImage, imageUrl, fieldType );
5498 3175 }
5499 3176
5500 - /**
5501 - * @since 5.0.04
5502 - */
5503 - label = frmAdminBuild.hooks.applyFilters( 'frm_choice_field_label', label, fieldId, optVals[ i ], hasImageOptions );
5504 -
5505 3177 checked = getChecked( optVals[ i ].id );
5506 3178
5507 3179 optObj = {
5508 3180 saved: saved,
@@ -5546,64 +3218,26 @@
5546 3218
5547 3219 return img.attr( 'src' );
5548 3220 }
5549 3221
5550 - function purifyHtml( html ) {
5551 - if ( html instanceof Element || html instanceof Document ) {
5552 - html = html.outerHTML;
5553 - }
5554 -
5555 - const clean = jQuery.parseHTML( html ).reduce(
5556 - ( total, currentNode ) => {
5557 - const cleanNode = frmDom.cleanNode( currentNode );
5558 -
5559 - if ( '#text' === cleanNode.nodeName ) {
5560 - return total += cleanNode.textContent;
5561 - }
5562 -
5563 - return total + cleanNode.outerHTML;
5564 - },
5565 - ''
5566 - );
5567 -
5568 - return clean;
5569 - }
5570 -
5571 3222 function getImageLabel( label, showLabelWithImage, imageUrl, fieldType ) {
5572 - var imageLabelClass,
3223 + var imageLabelClass, fullLabel,
5573 3224 originalLabel = label,
5574 - shape = fieldType === 'checkbox' ? 'square' : 'circle',
5575 - labelImage,
5576 - labelNode,
5577 - imageLabel;
3225 + shape = fieldType === 'checkbox' ? 'square' : 'circle';
5578 3226
5579 - originalLabel = purifyHtml( originalLabel );
5580 -
3227 + fullLabel = '<div class="frm_selected_checkmark"><svg class="frmsvg"><use xlink:href="#frm_checkmark_' + shape + '_icon"></svg></div>';
5581 3228 if ( imageUrl ) {
5582 - labelImage = img({ src: imageUrl, alt: originalLabel });
3229 + fullLabel += '<img src="' + imageUrl + '" alt="' + originalLabel + '" />';
5583 3230 } else {
5584 - labelImage = div({ className: 'frm_empty_url' });
5585 - labelImage.innerHTML = frm_admin_js.image_placeholder_icon; // eslint-disable-line camelcase
3231 + fullLabel += '<div class="frm_empty_url">' + frm_admin_js.image_placeholder_icon + '</div>';
5586 3232 }
3233 + if ( showLabelWithImage ) {
3234 + fullLabel += '<span class="frm_text_label_for_image"><span class="frm_text_label_for_image_inner">' + originalLabel + '</span></span>';
3235 + }
5587 3236
5588 3237 imageLabelClass = showLabelWithImage ? ' frm_label_with_image' : '';
5589 3238
5590 - imageLabel = tag( 'span', { className: 'frm_text_label_for_image_inner' });
5591 -
5592 - imageLabel.innerHTML = originalLabel;
5593 - labelNode = tag(
5594 - 'span',
5595 - {
5596 - className: 'frm_image_option_container' + imageLabelClass,
5597 - children: [
5598 - tag( 'div', { className: 'frm_selected_checkmark', child: svg({ href: '#frm_checkmark_' + shape + '_icon' }) }),
5599 - labelImage,
5600 - tag( 'span', { className: 'frm_text_label_for_image', child: imageLabel })
5601 - ]
5602 - }
5603 - );
5604 -
5605 - return labelNode;
3239 + return ( '<span class="frm_image_option_container' + imageLabelClass + '">' + fullLabel + '</span>' );
5606 3240 }
5607 3241
5608 3242 function getChecked( id ) {
5609 3243 field = jQuery( '#' + id );
@@ -5638,30 +3272,13 @@
5638 3272 /**
5639 3273 * Is the box checked to use images as options?
5640 3274 */
5641 3275 function imagesAsOptions( fieldId ) {
5642 - var checked = false,
5643 - field = document.getElementsByName( 'field_options[image_options_' + fieldId + ']' );
5644 -
5645 - for ( var i = 0; i < field.length; i++ ) {
5646 - if ( field[ i ].checked ) {
5647 - checked = '0' !== field[ i ].value;
5648 - }
5649 - }
5650 -
5651 - /**
5652 - * @since 5.0.04
5653 - */
5654 - return frmAdminBuild.hooks.applyFilters( 'frm_choice_field_images_as_options', checked, fieldId );
3276 + return isChecked( 'image_options_' + fieldId );
5655 3277 }
5656 3278
5657 3279 function showingLabelWithImage( fieldId ) {
5658 - const isShowing = ! isChecked( 'hide_image_text_' + fieldId );
5659 -
5660 - /**
5661 - * @since 5.0.04
5662 - */
5663 - return frmAdminBuild.hooks.applyFilters( 'frm_choice_field_showing_label_with_image', isShowing, fieldId );
3280 + return ! isChecked( 'hide_image_text_' + fieldId );
5664 3281 }
5665 3282
5666 3283 function isChecked( id ) {
5667 3284 var field = document.getElementById( id );
@@ -5671,27 +3288,20 @@
5671 3288 return field.checked;
5672 3289 }
5673 3290 }
5674 3291
5675 - function checkUniqueOpt( targetInput ) {
5676 - const settingsContainer = targetInput.closest( '.frm-single-settings' );
5677 - const fieldId = settingsContainer.getAttribute( 'data-fid' );
5678 - const areValuesSeparate = settingsContainer.querySelector( '[name="field_options[separate_value_' + fieldId + ']"]' ).checked;
5679 -
5680 - if ( areValuesSeparate && ! targetInput.name.endsWith( '[value]' ) ) {
5681 - return;
3292 + /* TODO: Is this still used? */
3293 + function checkUniqueOpt( id, text ) {
3294 + if ( id.indexOf( 'field_key_' ) === 0 ) {
3295 + var a = id.split( '-' );
3296 + jQuery.each( jQuery( 'label[id^="' + a[0] + '"]' ), function( k, v ) {
3297 + var c = false;
3298 + if ( ! c && jQuery( v ).attr( 'id' ) != id && jQuery( v ).html() == text ) {
3299 + c = true;
3300 + infoModal( 'Saved values cannot be identical.' );
3301 + }
3302 + });
5682 3303 }
5683 -
5684 - const container = document.getElementById( 'frm_field_' + fieldId + '_opts' );
5685 - const conflicts = Array.from( container.querySelectorAll( 'input[type="text"]' ) ).filter(
5686 - input => input.id !== targetInput.id &&
5687 - areValuesSeparate === input.name.endsWith( '[value]' ) &&
5688 - input.value === targetInput.value
5689 - );
5690 -
5691 - if ( conflicts.length ) {
5692 - infoModal( __( 'Duplicate option value "%s" detected', 'formidable' ).replace( '%s', purifyHtml( targetInput.value ) ) );
5693 - }
5694 3304 }
5695 3305
5696 3306 function setStarValues() {
5697 3307 /*jshint validthis:true */
@@ -5710,8 +3320,37 @@
5710 3320 container.append( '<input type="hidden" name="field_options[options_' + fieldID + '][' + i + ']" value="' + i + '"><input type="radio" name="item_meta[' + fieldID + ']" id="field_' + fieldKey + '-' + i + '" value="' + i + '" /><label for="field_' + fieldKey + '-' + i + '" class="star-rating"></label>' );
5711 3321 }
5712 3322 }
5713 3323
3324 + function setScaleValues() {
3325 + /*jshint validthis:true */
3326 + var isMin = this.id.indexOf( 'minnum' ) !== -1;
3327 + var fieldID = this.id.replace( 'scale_maxnum_', '' ).replace( 'scale_minnum_', '' );
3328 + var min = this.value;
3329 + var max = this.value;
3330 + if ( isMin ) {
3331 + max = document.getElementById( 'scale_maxnum_' + fieldID ).value;
3332 + } else {
3333 + min = document.getElementById( 'scale_minnum_' + fieldID ).value;
3334 + }
3335 +
3336 + updateScaleValues( parseInt( min, 10 ), parseInt( max, 10 ), fieldID );
3337 + }
3338 +
3339 + function updateScaleValues( min, max, fieldID ) {
3340 + var container = jQuery( '#field_' + fieldID + '_inner_container .frm_form_fields' );
3341 + container.html( '' );
3342 +
3343 + if ( min >= max ) {
3344 + max = min + 1;
3345 + }
3346 +
3347 + for ( var i = min; i <= max; i++ ) {
3348 + container.append( '<div class="frm_scale"><label><input type="hidden" name="field_options[options_' + fieldID + '][' + i + ']" value="' + i + '"> <input type="radio" name="item_meta[' + fieldID + ']" value="' + i + '"> ' + i + ' </label></div>' );
3349 + }
3350 + container.append( '<div class="clear"></div>' );
3351 + }
3352 +
5714 3353 function getFieldValues() {
5715 3354 /*jshint validthis:true */
5716 3355 var isTaxonomy,
5717 3356 val = this.value;
@@ -5791,17 +3430,17 @@
5791 3430 }
5792 3431 }
5793 3432
5794 3433 function updateFieldOrder() {
5795 - var fields, fieldId, field, currentOrder, newOrder;
3434 +
5796 3435 renumberPageBreaks();
5797 3436 jQuery( '#frm-show-fields' ).each( function( i ) {
5798 - fields = jQuery( 'li.frm_field_box', this );
3437 + var fields = jQuery( 'li.frm_field_box', this );
5799 3438 for ( i = 0; i < fields.length; i++ ) {
5800 - fieldId = fields[ i ].getAttribute( 'data-fid' );
5801 - field = jQuery( 'input[name="field_options[field_order_' + fieldId + ']"]' );
5802 - currentOrder = field.val();
5803 - newOrder = i + 1;
3439 + var fieldId = fields[ i ].getAttribute( 'data-fid' ),
3440 + field = jQuery( 'input[name="field_options[field_order_' + fieldId + ']"]' ),
3441 + currentOrder = field.val(),
3442 + newOrder = ( i + 1 );
5804 3443
5805 3444 if ( currentOrder != newOrder ) {
5806 3445 field.val( newOrder );
5807 3446 singleField = document.getElementById( 'frm-single-settings-' + fieldId );
@@ -5806,9 +3445,8 @@
5806 3445 field.val( newOrder );
5807 3446 singleField = document.getElementById( 'frm-single-settings-' + fieldId );
5808 3447
5809 3448 moveFieldSettings( singleField );
5810 - fieldUpdated();
5811 3449 }
5812 3450 }
5813 3451 });
5814 3452 }
@@ -5813,48 +3451,26 @@
5813 3451 });
5814 3452 }
5815 3453
5816 3454 function toggleSectionHolder() {
5817 - document.querySelectorAll( '.start_divider' ).forEach(
5818 - function( divider ) {
5819 - toggleOneSectionHolder( jQuery( divider ) );
5820 - }
5821 - );
3455 + jQuery( '.start_divider' ).each( function() {
3456 + toggleOneSectionHolder( jQuery( this ) );
3457 + });
5822 3458 }
5823 3459
5824 3460 function toggleOneSectionHolder( $section ) {
5825 - var noSectionFields, $rows, length, index, sectionHasFields;
5826 -
5827 - if ( ! $section.length ) {
3461 + if ( $section.length === 0 ) {
5828 3462 return;
5829 3463 }
5830 3464
5831 - $rows = $section.find( 'ul.frm_sorting' );
5832 - sectionHasFields = false;
5833 - length = $rows.length;
5834 - for ( index = 0; index < length; ++index ) {
5835 - if ( 0 !== getFieldsInRow( jQuery( $rows.get( index ) ) ).length ) {
5836 - sectionHasFields = true;
5837 - break;
5838 - }
3465 + var sectionFields = $section.parent( '.frm_field_box' ).children( '.frm_no_section_fields' );
3466 + if ( $section.children( 'li' ).length < 2 ) {
3467 + sectionFields.addClass( 'frm_block' );
3468 + } else {
3469 + sectionFields.removeClass( 'frm_block' );
5839 3470 }
5840 -
5841 - noSectionFields = $section.parent().children( '.frm_no_section_fields' ).get( 0 );
5842 - noSectionFields.classList.toggle( 'frm_block', ! sectionHasFields );
5843 3471 }
5844 3472
5845 - function handleShowPasswordLiveUpdate() {
5846 - frmDom.util.documentOn( 'change', '.frm_show_password_setting_input', event => {
5847 - const fieldId = event.target.getAttribute( 'data-fid' );
5848 - const fieldEl = document.getElementById( 'frm_field_id_' + fieldId );
5849 - if ( ! fieldEl ) {
5850 - return;
5851 - }
5852 -
5853 - fieldEl.classList.toggle( 'frm_disabled_show_password', ! event.target.checked );
5854 - });
5855 - }
5856 -
5857 3473 function slideDown() {
5858 3474 /*jshint validthis:true */
5859 3475 var id = jQuery( this ).data( 'slidedown' );
5860 3476 var $thisId = jQuery( document.getElementById( id ) );
@@ -5883,9 +3499,9 @@
5883 3499 }
5884 3500
5885 3501 function onEveryoneOptionSelected( $select ) {
5886 3502 $select.val( '' );
5887 - $select.next( '.btn-group' ).find( '.multiselect-container input[value!=""]' ).prop( 'checked', false );
3503 + $select.next( '.btn-group' ).find( '.multiselect-container li input[value!=""]' ).prop( 'checked', false );
5888 3504 }
5889 3505
5890 3506 function unselectEveryoneOptionIfSelected( $select ) {
5891 3507 var selectedValues = $select.val(),
@@ -5891,9 +3507,9 @@
5891 3507 var selectedValues = $select.val(),
5892 3508 index;
5893 3509
5894 3510 if ( selectedValues === null ) {
5895 - $select.next( '.btn-group' ).find( '.multiselect-container input[value=""]' ).prop( 'checked', true );
3511 + $select.next( '.btn-group' ).find( '.multiselect-container li input[value=""]' ).prop( 'checked', true );
5896 3512 onEveryoneOptionSelected( $select );
5897 3513 return;
5898 3514 }
5899 3515
@@ -5900,9 +3516,9 @@
5900 3516 index = selectedValues.indexOf( '' );
5901 3517 if ( index >= 0 ) {
5902 3518 selectedValues.splice( index, 1 );
5903 3519 $select.val( selectedValues );
5904 - $select.next( '.btn-group' ).find( '.multiselect-container input[value=""]' ).prop( 'checked', false );
3520 + $select.next( '.btn-group' ).find( '.multiselect-container li input[value=""]' ).prop( 'checked', false );
5905 3521 }
5906 3522 }
5907 3523
5908 3524 /**
@@ -5935,9 +3551,9 @@
5935 3551 }
5936 3552 replaceWith += ' ';
5937 3553
5938 3554 // Allow for the column number dropdown.
5939 - replaceWith = replaceWith.replace( ' block ', ' ' ).replace( ' inline ', ' horizontal_radio ' );
3555 + replaceWith = replaceWith.replace( ' block ', ' ' ).replace( ' inline ', ' horizontal_radio ' ).replace( ' frm_alignright ', ' ' );
5940 3556
5941 3557 classes = field.className.split( ' frmstart ' )[1];
5942 3558 classes = 0 === classes.indexOf( 'frmend ' ) ? '' : classes.split( ' frmend ' )[0];
5943 3559
@@ -6006,10 +3622,8 @@
6006 3622 if ( action[i] === 'updateOption' ) {
6007 3623 changeHiddenSeparateValue( this );
6008 3624 } else if ( action[i] === 'updateDefault' ) {
6009 3625 changeDefaultRadioValue( this );
6010 - } else if ( action[i] === 'checkUniqueOpt' ) {
6011 - checkUniqueOpt( this );
6012 3626 } else {
6013 3627 this.value = this.value[ action[i] ]();
6014 3628 }
6015 3629 }
@@ -6063,9 +3677,10 @@
6063 3677 }
6064 3678
6065 3679 function submitBuild() {
6066 3680 /*jshint validthis:true */
6067 - var $thisEle = this;
3681 + var $thisEle = jQuery( this );
3682 + var p = $thisEle.html();
6068 3683
6069 3684 preFormSave( this );
6070 3685
6071 3686 var $form = jQuery( builderForm );
@@ -6076,9 +3691,9 @@
6076 3691 type: 'POST',
6077 3692 url: ajaxurl,
6078 3693 data: {action: 'frm_save_form', 'frm_compact_fields': v, nonce: frmGlobal.nonce},
6079 3694 success: function( msg ) {
6080 - afterFormSave( $thisEle );
3695 + afterFormSave( $thisEle, p );
6081 3696
6082 3697 var $postStuff = document.getElementById( 'post-body-content' );
6083 3698 var $html = document.createElement( 'div' );
6084 3699 $html.setAttribute( 'class', 'frm_updated_message' );
@@ -6118,289 +3733,127 @@
6118 3733 if ( jQuery( 'form.inplace_form' ).length ) {
6119 3734 jQuery( '.inplace_save, .postbox' ).trigger( 'click' );
6120 3735 }
6121 3736
6122 - if ( b.classList.contains( 'frm_button_submit' ) ) {
6123 - b.classList.add( 'frm_loading_form' );
3737 + $button = jQuery( b );
3738 +
3739 + if ( $button.hasClass( 'frm_button_submit' ) ) {
3740 + $button.addClass( 'frm_loading_form' );
3741 + $button.html( frm_admin_js.saving );
6124 3742 } else {
6125 - b.classList.add( 'frm_loading_button' );
3743 + $button.addClass( 'frm_loading_button' );
3744 + $button.val( frm_admin_js.saving );
6126 3745 }
6127 - b.setAttribute( 'aria-busy', 'true' );
6128 3746 }
6129 3747
6130 - function afterFormSave( button ) {
6131 - button.classList.remove( 'frm_loading_form' );
6132 - button.classList.remove( 'frm_loading_button' );
3748 + function afterFormSave( $button, buttonVal ) {
3749 + $button.removeClass( 'frm_loading_form' ).removeClass( 'frm_loading_button' );
3750 + $button.html( frm_admin_js.saved );
6133 3751 resetOptionTextDetails();
6134 3752 fieldsUpdated = 0;
6135 - button.setAttribute( 'aria-busy', 'false' );
6136 3753
6137 3754 setTimeout( function() {
6138 3755 jQuery( '.frm_updated_message' ).fadeOut( 'slow', function() {
6139 3756 this.parentNode.removeChild( this );
6140 3757 });
3758 + $button.fadeOut( 'slow', function() {
3759 + $button.html( buttonVal );
3760 + $button.show();
3761 + });
6141 3762 }, 5000 );
6142 3763 }
6143 3764
6144 3765 function initUpgradeModal() {
6145 - const $info = initModal( '#frm_upgrade_modal' );
3766 + var $info = initModal( '#frm_upgrade_modal' );
6146 3767 if ( $info === false ) {
6147 3768 return;
6148 3769 }
6149 3770
6150 - document.addEventListener( 'click', handleUpgradeClick );
3771 + jQuery( document ).on( 'click', '[data-upgrade]', function( event ) {
3772 + var upgradeLabel, requires, button, link, content;
6151 3773
6152 - function handleUpgradeClick( event ) {
6153 - let element, link, content;
3774 + event.preventDefault();
3775 + upgradeLabel = this.getAttribute( 'data-upgrade' );
6154 3776
6155 - element = event.target;
6156 -
6157 - if ( ! element.classList ) {
3777 + if ( '' === upgradeLabel ) {
3778 + // if the upgrade level is empty, it's because this upgrade is already active.
6158 3779 return;
6159 3780 }
6160 3781
6161 - const showExpiredModal = element.classList.contains( 'frm_show_expired_modal' ) || null !== element.querySelector( '.frm_show_expired_modal' ) || element.closest( '.frm_show_expired_modal' );
3782 + jQuery( '#frm_upgrade_modal .frm_lock_icon' ).removeClass( 'frm_lock_open_icon' );
3783 + jQuery( '#frm_upgrade_modal .frm_lock_icon use' ).attr( 'xlink:href', '#frm_lock_icon' );
6162 3784
6163 - if ( ! element.dataset.upgrade ) {
6164 - const parent = element.closest( '[data-upgrade]' );
6165 - if ( ! parent ) {
6166 - return;
6167 - }
6168 - element = parent;
3785 + requires = this.getAttribute( 'data-requires' );
3786 + if ( typeof requires === 'undefined' || requires === null || requires === '' ) {
3787 + requires = 'Pro';
6169 3788 }
3789 + jQuery( '.license-level' ).text( requires );
6170 3790
6171 - if ( showExpiredModal ) {
6172 - const hookName = 'frm_show_expired_modal';
6173 - wp.hooks.doAction( hookName, element );
6174 - return;
6175 - }
6176 -
6177 - const upgradeLabel = element.dataset.upgrade;
6178 - if ( ! upgradeLabel || element.classList.contains( 'frm_show_upgrade_tab' ) ) {
6179 - return;
6180 - }
6181 -
6182 - event.preventDefault();
6183 -
6184 - const modal = $info.get( 0 );
6185 - const lockIcon = modal.querySelector( '.frm_lock_icon' );
6186 -
6187 - if ( lockIcon ) {
6188 - lockIcon.style.display = 'block';
6189 - lockIcon.classList.remove( 'frm_lock_open_icon' );
6190 - lockIcon.querySelector( 'use' ).setAttribute( 'href', '#frm_lock_icon' );
6191 - }
6192 -
6193 - const upgradeImageId = 'frm_upgrade_modal_image';
6194 - const oldImage = document.getElementById( upgradeImageId );
6195 - if ( oldImage ) {
6196 - oldImage.remove();
6197 - }
6198 -
6199 - if ( element.dataset.image ) {
6200 - if ( lockIcon ) {
6201 - lockIcon.style.display = 'none';
6202 - }
6203 - lockIcon.parentNode.insertBefore( img({ id: upgradeImageId, src: frmGlobal.url + '/images/' + element.dataset.image }), lockIcon );
6204 - }
6205 -
6206 - const level = modal.querySelector( '.license-level' );
6207 - if ( level ) {
6208 - level.textContent = getRequiredLicenseFromTrigger( element );
6209 - }
6210 -
6211 3791 // If one click upgrade, hide other content
6212 - addOneClick( element, 'modal', upgradeLabel );
3792 + addOneClickModal( this );
6213 3793
6214 - modal.querySelector( '.frm_are_not_installed' ).style.display = element.dataset.image ? 'none' : 'inline-block';
6215 - modal.querySelector( '.frm_feature_label' ).textContent = upgradeLabel;
6216 - modal.querySelector( 'h2' ).style.display = 'block';
3794 + jQuery( '.frm_feature_label' ).text( upgradeLabel );
3795 + jQuery( '#frm_upgrade_modal h2' ).show();
6217 3796
6218 3797 $info.dialog( 'open' );
6219 3798
6220 3799 // set the utm medium
6221 - const button = modal.querySelector( '.button-primary:not(.frm-oneclick-button)' );
6222 - link = button.getAttribute( 'href' ).replace( /(medium=)[a-z_-]+/ig, '$1' + element.getAttribute( 'data-medium' ) );
6223 - content = element.getAttribute( 'data-content' );
6224 - if ( content === null ) {
3800 + button = $info.find( '.button-primary:not(#frm-oneclick-button)' );
3801 + link = button.attr( 'href' ).replace( /(medium=)[a-z_-]+/ig, '$1' + this.getAttribute( 'data-medium' ) );
3802 + content = this.getAttribute( 'data-content' );
3803 + if ( content === undefined ) {
6225 3804 content = '';
6226 3805 }
6227 3806 link = link.replace( /(content=)[a-z_-]+/ig, '$1' + content );
6228 - button.setAttribute( 'href', link );
6229 - }
6230 - }
6231 -
6232 - function getRequiredLicenseFromTrigger( element ) {
6233 - if ( element.dataset.requires ) {
6234 - return element.dataset.requires;
6235 - }
6236 - return 'Pro';
6237 - }
6238 -
6239 - function populateUpgradeTab( element ) {
6240 - const title = element.dataset.upgrade;
6241 -
6242 - const tab = element.getAttribute( 'href' ).replace( '#', '' );
6243 - const container = document.querySelector( '.frm_' + tab ) || document.querySelector( '.' + tab );
6244 -
6245 - if ( ! container ) {
6246 - return;
6247 - }
6248 -
6249 - if ( container.querySelector( '.frm-upgrade-message' ) ) {
6250 - // Tab has already been populated.
6251 - return;
6252 - }
6253 -
6254 - const h2 = container.querySelector( 'h2' );
6255 - h2.style.borderBottom = 'none';
6256 -
6257 - /* translators: %s: Form Setting section name (ie Form Permissions, Form Scheduling). */
6258 - h2.textContent = __( '%s are not installed' ).replace( '%s', title );
6259 -
6260 - container.classList.add( 'frmcenter' );
6261 -
6262 - const upgradeModal = document.getElementById( 'frm_upgrade_modal' );
6263 - appendClonedModalElementToContainer( 'frm-oneclick' );
6264 - appendClonedModalElementToContainer( 'frm-addon-status' );
6265 -
6266 - // Borrow the call to action from the Upgrade upgradeModal which should exist on the settings page (it is still used for other upgrades including Actions).
6267 - const upgradeModalLink = upgradeModal.querySelector( '.frm-upgrade-link' );
6268 - if ( upgradeModalLink ) {
6269 - const upgradeButton = upgradeModalLink.cloneNode( true );
6270 - const level = upgradeButton.querySelector( '.license-level' );
6271 -
6272 - if ( level ) {
6273 - level.textContent = getRequiredLicenseFromTrigger( element );
6274 - }
6275 -
6276 - container.appendChild( upgradeButton );
6277 -
6278 - // Maybe append the secondary "Already purchased?" link from the upgradeModal as well.
6279 - if ( upgradeModalLink.nextElementSibling && upgradeModalLink.nextElementSibling.querySelector( '.frm-link-secondary' ) ) {
6280 - container.appendChild( upgradeModalLink.nextElementSibling.cloneNode( true ) );
6281 - }
6282 -
6283 - appendClonedModalElementToContainer( 'frm-oneclick-button' );
6284 - }
6285 -
6286 - appendClonedModalElementToContainer( 'frm-upgrade-message' );
6287 - addOneClick( element, 'tab', element.dataset.message );
6288 -
6289 - if ( element.dataset.screenshot ) {
6290 - container.appendChild( getScreenshotWrapper( element.dataset.screenshot ) );
6291 - }
6292 -
6293 - function appendClonedModalElementToContainer( className ) {
6294 - container.appendChild( upgradeModal.querySelector( '.' + className ).cloneNode( true ) );
6295 - }
6296 - }
6297 -
6298 - function getScreenshotWrapper( screenshot ) {
6299 - const folderUrl = frmGlobal.url + '/images/screenshots/';
6300 - const wrapper = div({
6301 - className: 'frm-settings-screenshot-wrapper',
6302 - children: [
6303 - getToolbar(),
6304 - div({ child: img({ src: folderUrl + screenshot }) })
6305 - ]
3807 + button.attr( 'href', link );
3808 + return false;
6306 3809 });
6307 -
6308 - function getToolbar() {
6309 - const children = getColorIcons();
6310 - children.push( img({ src: frmGlobal.url + '/images/tab.svg' }) );
6311 - return div({
6312 - className: 'frm-settings-screenshot-toolbar',
6313 - children
6314 - });
6315 - }
6316 -
6317 - function getColorIcons() {
6318 - return [ '#ED8181', '#EDE06A', '#80BE30' ].map(
6319 - color => {
6320 - const circle = div({ className: 'frm-minmax-icon' });
6321 - circle.style.backgroundColor = color;
6322 - return circle;
6323 - }
6324 - );
6325 - }
6326 -
6327 - return wrapper;
6328 3810 }
6329 3811
6330 3812 /**
6331 3813 * Allow addons to be installed from the upgrade modal.
6332 - *
6333 - * @param {Element} link
6334 - * @param {String} context Either 'modal' or 'tab'.
6335 - * @param {String|undefined} upgradeLabel
6336 3814 */
6337 - function addOneClick( link, context, upgradeLabel ) {
6338 - let container;
3815 + function addOneClickModal( link ) {
3816 + var oneclickMessage = document.getElementById( 'frm-oneclick' ),
3817 + oneclick = link.getAttribute( 'data-oneclick' ),
3818 + customLink = link.getAttribute( 'data-link' ),
3819 + showLink = document.getElementById( 'frm-upgrade-modal-link' ),
3820 + upgradeMessage = document.getElementById( 'frm-upgrade-message' ),
3821 + newMessage = link.getAttribute( 'data-message' ),
3822 + button = document.getElementById( 'frm-oneclick-button' ),
3823 + showIt = 'block',
3824 + hideIt = 'none';
6339 3825
6340 - if ( 'modal' === context ) {
6341 - container = document.getElementById( 'frm_upgrade_modal' );
6342 - } else if ( 'tab' === context ) {
6343 - container = document.getElementById( link.getAttribute( 'href' ).substr( 1 ) );
6344 - } else {
6345 - return;
6346 - }
6347 -
6348 - const oneclickMessage = container.querySelector( '.frm-oneclick' );
6349 - const upgradeMessage = container.querySelector( '.frm-upgrade-message' );
6350 - const showLink = container.querySelector( '.frm-upgrade-link' );
6351 - const button = container.querySelector( '.frm-oneclick-button' );
6352 - const addonStatus = container.querySelector( '.frm-addon-status' );
6353 -
6354 - let oneclick = link.getAttribute( 'data-oneclick' );
6355 - let newMessage = link.getAttribute( 'data-message' );
6356 - let showIt = 'block';
6357 - let showMsg = 'block';
6358 - let hideIt = 'none';
6359 -
6360 3826 // If one click upgrade, hide other content.
6361 3827 if ( oneclickMessage !== null && typeof oneclick !== 'undefined' && oneclick ) {
6362 - if ( newMessage === null ) {
6363 - showMsg = 'none';
6364 - }
6365 3828 showIt = 'none';
6366 3829 hideIt = 'block';
6367 3830 oneclick = JSON.parse( oneclick );
6368 3831
6369 - button.className = button.className.replace( ' frm-install-addon', '' ).replace( ' frm-activate-addon', '' );
6370 - button.className = button.className + ' ' + oneclick.class;
6371 - button.textContent = __( 'Activate', 'formidable' );
3832 + button.className = button.className.replace( ' frm-install-addon', '' ).replace( ' frm-activate-addon', '' );
3833 + button.className = button.className + ' ' + oneclick.class;
6372 3834 button.rel = oneclick.url;
6373 3835 }
6374 3836
6375 - if ( ! newMessage ) {
3837 + // Use a custom message in the modal.
3838 + if ( newMessage === null || typeof newMessage === 'undefined' || newMessage === '' ) {
6376 3839 newMessage = upgradeMessage.getAttribute( 'data-default' );
6377 3840 }
6378 - if ( undefined !== upgradeLabel ) {
6379 - newMessage = newMessage.replace( '<span class="frm_feature_label"></span>', upgradeLabel );
6380 - }
6381 -
6382 3841 upgradeMessage.innerHTML = newMessage;
6383 3842
6384 3843 // Either set the link or use the default.
6385 - showLink.href = getShowLinkHrefValue( link, showLink );
3844 + if ( customLink === null || typeof customLink === 'undefined' || customLink === '' ) {
3845 + customLink = showLink.getAttribute( 'data-default' );
3846 + }
3847 + showLink.href = customLink;
6386 3848
6387 - addonStatus.style.display = 'none';
6388 -
3849 + document.getElementById( 'frm-addon-status' ).style.display = 'none';
6389 3850 oneclickMessage.style.display = hideIt;
6390 3851 button.style.display = hideIt === 'block' ? 'inline-block' : hideIt;
6391 - upgradeMessage.style.display = showMsg;
3852 + upgradeMessage.style.display = showIt;
6392 3853 showLink.style.display = showIt === 'block' ? 'inline-block' : showIt;
6393 3854 }
6394 3855
6395 - function getShowLinkHrefValue( link, showLink ) {
6396 - let customLink = link.getAttribute( 'data-link' );
6397 - if ( customLink === null || typeof customLink === 'undefined' || customLink === '' ) {
6398 - customLink = showLink.getAttribute( 'data-default' );
6399 - }
6400 - return customLink;
6401 - }
6402 -
6403 3856 /* Form settings */
6404 3857
6405 3858 function showInputIcon( parentClass ) {
6406 3859 if ( typeof parentClass === 'undefined' ) {
@@ -6438,79 +3891,41 @@
6438 3891 jQuery( '.' + c + '_action_message_box.' + c + '_action_box' ).fadeIn( 'slow' );
6439 3892 }
6440 3893 }
6441 3894
6442 - function copyFormAction( event ) {
6443 - if ( waitForActionToLoadBeforeCopy( event.target ) ) {
3895 + function copyFormAction() {
3896 + /*jshint validthis:true */
3897 + if ( waitForActionToLoadBeforeCopy( this ) ) {
6444 3898 return;
6445 3899 }
6446 3900
6447 - const targetSettings = event.target.closest( '.frm_form_action_settings' );
6448 - const wysiwyg = targetSettings.querySelector( '.wp-editor-area' );
6449 - if ( wysiwyg ) {
6450 - // Temporary remove TinyMCE before cloning to avoid TinyMCE conflicts.
6451 - tinymce.EditorManager.execCommand( 'mceRemoveEditor', true, wysiwyg.id );
6452 - }
3901 + var action = jQuery( this ).closest( '.frm_form_action_settings' ).clone();
3902 + var currentID = action.attr( 'id' ).replace( 'frm_form_action_', '' );
3903 + var newID = newActionId( currentID );
3904 + action.find( '.frm_action_id, .frm-btn-group' ).remove();
3905 + action.find( 'input[name$="[' + currentID + '][ID]"]' ).val( '' );
3906 + action.find( '.widget-inside' ).hide();
6453 3907
6454 - const $action = jQuery( targetSettings ).clone();
6455 - const currentID = $action.attr( 'id' ).replace( 'frm_form_action_', '' );
6456 - const newID = newActionId( currentID );
6457 -
6458 - $action.find( '.frm_action_id, .frm-btn-group' ).remove();
6459 - $action.find( 'input[name$="[' + currentID + '][ID]"]' ).val( '' );
6460 - $action.find( '.widget-inside' ).hide();
6461 -
6462 3908 // the .html() gets original values, so they need to be set
6463 - $action.find( 'input[type=text], textarea, input[type=number]' ).prop( 'defaultValue', function() {
3909 + action.find( 'input[type=text], textarea, input[type=number]' ).prop( 'defaultValue', function() {
6464 3910 return this.value;
6465 3911 });
6466 3912
6467 - $action.find( 'input[type=checkbox], input[type=radio]' ).prop( 'defaultChecked', function() {
3913 + action.find( 'input[type=checkbox], input[type=radio]' ).prop( 'defaultChecked', function() {
6468 3914 return this.checked;
6469 3915 });
6470 3916
6471 - const rename = new RegExp( '\\[' + currentID + '\\]', 'g' );
6472 - const reid = new RegExp( '_' + currentID + '"', 'g' );
6473 - const reclass = new RegExp( '-' + currentID + '"', 'g' );
6474 - const revalue = new RegExp( '"' + currentID + '"', 'g' ); // if a field id matches, this could cause trouble
3917 + var rename = new RegExp( '\\[' + currentID + '\\]', 'g' );
3918 + var reid = new RegExp( '_' + currentID + '"', 'g' );
3919 + var reclass = new RegExp( '-' + currentID + '"', 'g' );
3920 + var revalue = new RegExp( '"' + currentID + '"', 'g' ); // if a field id matches, this could cause trouble
6475 3921
6476 - let html = $action.html().replace( rename, '[' + newID + ']' ).replace( reid, '_' + newID + '"' );
3922 + var html = action.html().replace( rename, '[' + newID + ']' ).replace( reid, '_' + newID + '"' );
6477 3923 html = html.replace( reclass, '-' + newID + '"' ).replace( revalue, '"' + newID + '"' );
3924 + var div = '<div id="frm_form_action_' + newID + '" class="widget frm_form_action_settings frm_single_email_settings" data-actionkey="' + newID + '">';
6478 3925
6479 - const newAction = div({
6480 - id: 'frm_form_action_' + newID,
6481 - className: $action.get( 0 ).className
6482 - });
6483 - newAction.setAttribute( 'data-actionkey', newID );
6484 - newAction.innerHTML = html;
6485 - newAction.querySelectorAll( '.wp-editor-wrap, .wp-editor-wrap *' ).forEach(
6486 - element => {
6487 - if ( 'string' === typeof element.className ) {
6488 - element.className = element.className.replace( currentID, newID );
6489 - }
6490 - element.id = element.id.replace( currentID, newID );
6491 - }
6492 - );
6493 - newAction.classList.remove( 'open' );
6494 - document.getElementById( 'frm_notification_settings' ).appendChild( newAction );
6495 -
6496 - if ( wysiwyg ) {
6497 - // Re-initialize the original wysiwyg which was removed before cloning.
6498 - frmDom.wysiwyg.init( wysiwyg );
6499 - frmDom.wysiwyg.init( newAction.querySelector( '.wp-editor-area' ) );
6500 - }
6501 -
6502 - if ( newAction.classList.contains( 'frm_single_on_submit_settings' ) ) {
6503 - const autocompleteInput = newAction.querySelector( 'input.frm-page-search' );
6504 - if ( autocompleteInput ) {
6505 - frmDom.autocomplete.initAutocomplete( 'page', newAction );
6506 - }
6507 - }
6508 -
3926 + jQuery( '#frm_notification_settings' ).append( div + html + '</div>' );
6509 3927 initiateMultiselect();
6510 -
6511 - const hookName = 'frm_after_duplicate_action';
6512 - wp.hooks.doAction( hookName, newAction );
6513 3928 }
6514 3929
6515 3930 function waitForActionToLoadBeforeCopy( element ) {
6516 3931 var $trigger = jQuery( element ),
@@ -6543,21 +3958,23 @@
6543 3958 }
6544 3959
6545 3960 function addFormAction() {
6546 3961 /*jshint validthis:true */
6547 - const type = jQuery( this ).data( 'actiontype' );
3962 + var type, actionId, formId, placeholderSetting, actionsList;
6548 3963
3964 + type = jQuery( this ).data( 'actiontype' );
3965 +
6549 3966 if ( isAtLimitForActionType( type ) ) {
6550 3967 return;
6551 3968 }
6552 3969
6553 - const actionId = getNewActionId();
6554 - const formId = thisFormId;
3970 + actionId = getNewActionId();
3971 + formId = thisFormId;
6555 3972
6556 - const placeholderSetting = document.createElement( 'div' );
3973 + placeholderSetting = document.createElement( 'div' );
6557 3974 placeholderSetting.classList.add( 'frm_single_' + type + '_settings' );
6558 3975
6559 - const actionsList = document.getElementById( 'frm_notification_settings' );
3976 + actionsList = document.getElementById( 'frm_notification_settings' );
6560 3977 actionsList.appendChild( placeholderSetting );
6561 3978
6562 3979 jQuery.ajax({
6563 3980 type: 'POST',
@@ -6568,62 +3985,35 @@
6568 3985 list_id: actionId,
6569 3986 form_id: formId,
6570 3987 nonce: frmGlobal.nonce
6571 3988 },
6572 - success: handleAddFormActionSuccess
6573 - });
3989 + success: function( html ) {
3990 + fieldUpdated();
3991 + placeholderSetting.remove();
6574 3992
6575 - function handleAddFormActionSuccess( html ) {
6576 - fieldUpdated();
6577 - placeholderSetting.remove();
3993 + // Close any open actions first.
3994 + jQuery( '.frm_form_action_settings.open' ).removeClass( 'open' );
6578 3995
6579 - closeOpenActions();
3996 + jQuery( actionsList ).append( html );
3997 + jQuery( '.frm_form_action_settings' ).fadeIn( 'slow' );
6580 3998
6581 - const newActionContainer = div();
6582 - newActionContainer.innerHTML = html;
3999 + var newAction = document.getElementById( 'frm_form_action_' + actionId );
6583 4000
6584 - const widgetTop = newActionContainer.querySelector( '.widget-top' );
6585 - Array.from( newActionContainer.children ).forEach( child => actionsList.appendChild( child ) );
4001 + newAction.classList.add( 'open' );
4002 + document.getElementById( 'post-body-content' ).scroll({
4003 + top: newAction.offsetTop + 10,
4004 + left: 0,
4005 + behavior: 'smooth'
4006 + });
6586 4007
6587 - jQuery( '.frm_form_action_settings' ).fadeIn( 'slow' );
6588 -
6589 - const newAction = document.getElementById( 'frm_form_action_' + actionId );
6590 -
6591 - newAction.classList.add( 'open' );
6592 - document.getElementById( 'post-body-content' ).scroll({
6593 - top: newAction.offsetTop + 10,
6594 - left: 0,
6595 - behavior: 'smooth'
6596 - });
6597 -
6598 - // Check if icon should be active
6599 - checkActiveAction( type );
6600 - showInputIcon( '#frm_form_action_' + actionId );
6601 -
6602 - initiateMultiselect();
6603 - frmDom.autocomplete.initAutocomplete( 'page', newAction );
6604 -
6605 - if ( widgetTop ) {
6606 - jQuery( widgetTop ).trigger( 'frm-action-loaded' );
4008 + //check if icon should be active
4009 + checkActiveAction( type );
4010 + initiateMultiselect();
4011 + showInputIcon( '#frm_form_action_' + actionId );
6607 4012 }
6608 -
6609 - /**
6610 - * Fires after added a new form action.
6611 - *
6612 - * @since 5.5.4
6613 - *
6614 - * @param {HTMLElement} formAction Form action element.
6615 - */
6616 - frmAdminBuild.hooks.doAction( 'frm_added_form_action', newAction );
6617 - }
4013 + });
6618 4014 }
6619 4015
6620 - function closeOpenActions() {
6621 - document.querySelectorAll( '.frm_form_action_settings.open' ).forEach(
6622 - setting => setting.classList.remove( 'open' )
6623 - );
6624 - }
6625 -
6626 4016 function toggleActionGroups() {
6627 4017 /*jshint validthis:true */
6628 4018 var actions = document.getElementById( 'frm_email_addon_menu' ).classList,
6629 4019 search = document.getElementById( 'actions-search-input' );
@@ -6665,8 +4055,9 @@
6665 4055 }
6666 4056
6667 4057 deselectFields();
6668 4058 $thisobj.addClass( 'selected' );
4059 +
6669 4060 showFieldOptions( obj );
6670 4061 }
6671 4062
6672 4063 /**
@@ -6690,45 +4081,10 @@
6690 4081 }
6691 4082
6692 4083 singleField.classList.remove( 'frm_hidden' );
6693 4084 document.getElementById( 'frm-options-panel-tab' ).click();
6694 -
6695 - const editor = singleField.querySelector( '.wp-editor-area' );
6696 - if ( editor ) {
6697 - frmDom.wysiwyg.init(
6698 - editor,
6699 - { setupCallback: setupTinyMceEventHandlers }
6700 - );
6701 - }
6702 4085 }
6703 4086
6704 - function setupTinyMceEventHandlers( editor ) {
6705 - editor.on( 'Change', function() {
6706 - handleTinyMceChange( editor );
6707 - });
6708 - }
6709 -
6710 - function handleTinyMceChange( editor ) {
6711 - if ( ! isTinyMceActive() || tinyMCE.activeEditor.isHidden() ) {
6712 - return;
6713 - }
6714 -
6715 - editor.targetElm.value = editor.getContent();
6716 - jQuery( editor.targetElm ).trigger( 'change' );
6717 - }
6718 -
6719 - function isTinyMceActive() {
6720 - var activeSettings, wrapper;
6721 -
6722 - activeSettings = document.querySelector( '.frm-single-settings:not(.frm_hidden)' );
6723 - if ( ! activeSettings ) {
6724 - return false;
6725 - }
6726 -
6727 - wrapper = activeSettings.querySelector( '.wp-editor-wrap' );
6728 - return null !== wrapper && wrapper.classList.contains( 'tmce-active' );
6729 - }
6730 -
6731 4087 /**
6732 4088 * Move the settings to the sidebar the first time they are changed or selected.
6733 4089 * Keep the end marker at the end of the form.
6734 4090 */
@@ -6781,53 +4137,25 @@
6781 4137 }
6782 4138 }
6783 4139
6784 4140 function checkActiveAction( type ) {
6785 - const actionTriggers = document.querySelectorAll( '.frm_' + type + '_action' );
4141 + var $actionTriggers, limitClass;
6786 4142
4143 + $actionTriggers = jQuery( '.frm_' + type + '_action' );
4144 +
6787 4145 if ( isAtLimitForActionType( type ) ) {
6788 - const addAlreadyUsedClass = getLimitForActionType( type ) > 0;
6789 - markActionTriggersInactive( actionTriggers, addAlreadyUsedClass );
6790 - return;
4146 + limitClass = 'frm_inactive_action';
4147 + if ( getLimitForActionType( type ) > 0 ) {
4148 + limitClass += ' frm_already_used';
4149 + }
4150 + $actionTriggers.removeClass( 'frm_active_action' ).addClass( limitClass );
4151 + } else {
4152 + $actionTriggers.removeClass( 'frm_inactive_action frm_already_used' ).addClass( 'frm_active_action' );
6791 4153 }
6792 -
6793 - markActionTriggersActive( actionTriggers );
6794 4154 }
6795 4155
6796 - function markActionTriggersActive( triggers ) {
6797 - triggers.forEach(
6798 - trigger => {
6799 - if ( trigger.querySelector( '.frm_show_upgrade' ) ) {
6800 - // Prevent disabled action becoming active.
6801 - return;
6802 - }
6803 -
6804 - trigger.classList.remove( 'frm_inactive_action', 'frm_already_used' );
6805 - trigger.classList.add( 'frm_active_action' );
6806 - }
6807 - );
6808 - }
6809 -
6810 - function markActionTriggersInactive( triggers, addAlreadyUsedClass ) {
6811 - triggers.forEach(
6812 - trigger => {
6813 - trigger.classList.remove( 'frm_active_action' );
6814 - trigger.classList.add( 'frm_inactive_action' );
6815 - if ( addAlreadyUsedClass ) {
6816 - trigger.classList.add( 'frm_already_used' );
6817 - }
6818 - }
6819 - );
6820 - }
6821 -
6822 4156 function isAtLimitForActionType( type ) {
6823 - let atLimit = getNumberOfActionsForType( type ) >= getLimitForActionType( type );
6824 -
6825 - const hookName = 'frm_action_at_limit';
6826 - const hookArgs = { type };
6827 - atLimit = wp.hooks.applyFilters( hookName, atLimit, hookArgs );
6828 -
6829 - return atLimit;
4157 + return getNumberOfActionsForType( type ) >= getLimitForActionType( type );
6830 4158 }
6831 4159
6832 4160 function getLimitForActionType( type ) {
6833 4161 return parseInt( jQuery( '.frm_' + type + '_action' ).data( 'limit' ), 10 );
@@ -6837,9 +4165,9 @@
6837 4165 return jQuery( '.frm_single_' + type + '_settings' ).length;
6838 4166 }
6839 4167
6840 4168 function onlyOneActionMessage() {
6841 - infoModal( frm_admin_js.only_one_action ); // eslint-disable-line camelcase
4169 + infoModal( frm_admin_js.only_one_action );
6842 4170 }
6843 4171
6844 4172 function addFormLogicRow() {
6845 4173 /*jshint validthis:true */
@@ -6927,8 +4255,35 @@
6927 4255 //TODO: add < > if they aren't there
6928 4256 }*/
6929 4257 }
6930 4258
4259 + function maybeShowFormMessages() {
4260 + var header = document.getElementById( 'frm_messages_header' );
4261 + if ( showFormMessages() ) {
4262 + header.style.display = 'block';
4263 + } else {
4264 + header.style.display = 'none';
4265 + }
4266 + }
4267 +
4268 + function showFormMessages() {
4269 + var action = document.getElementById( 'success_action' );
4270 + var selectedAction = action.options[action.selectedIndex].value;
4271 + if ( selectedAction === 'message' ) {
4272 + return true;
4273 + }
4274 +
4275 + var show = false;
4276 + var editable = document.getElementById( 'editable' );
4277 + if ( editable !== null ) {
4278 + show = editable.checked && jQuery( document.getElementById( 'edit_action' ) ).val() === 'message';
4279 + if ( ! show ) {
4280 + show = isChecked( 'save_draft' );
4281 + }
4282 + }
4283 + return show;
4284 + }
4285 +
6931 4286 function checkDupPost() {
6932 4287 /*jshint validthis:true */
6933 4288 var postField = jQuery( 'select.frm_single_post_field' );
6934 4289 postField.css( 'border-color', '' );
@@ -6940,9 +4295,9 @@
6940 4295 postField.each( function() {
6941 4296 if ( jQuery( this ).val() === v && this.name !== $t.name ) {
6942 4297 this.style.borderColor = 'red';
6943 4298 jQuery( $t ).val( '' );
6944 - infoModal( frm_admin_js.field_already_used ); // eslint-disable-line camelcase
4299 + infoModal( 'Oops. You have already used that field.' );
6945 4300 return false;
6946 4301 }
6947 4302 });
6948 4303 }
@@ -6987,9 +4342,8 @@
6987 4342 // update all rows of categories/taxonomies
6988 4343 var curSelect, newSelect,
6989 4344 catRows = document.getElementById( 'frm_posttax_rows' ).childNodes,
6990 4345 postParentField = document.querySelector( '.frm_post_parent_field' ),
6991 - postMenuOrderField = document.querySelector( '.frm_post_menu_order_field' ),
6992 4346 postType = this.value;
6993 4347
6994 4348 // Get new category/taxonomy options
6995 4349 jQuery.ajax({
@@ -7025,58 +4379,40 @@
7025 4379 });
7026 4380
7027 4381 // Get new post parent option.
7028 4382 if ( postParentField ) {
7029 - getActionOption(
7030 - postParentField,
7031 - postType,
7032 - 'frm_get_post_parent_option',
7033 - function( response, optName ) {
7034 - // The replaced string is declared in FrmProFormActionController::ajax_get_post_menu_order_option() in the pro version.
7035 - postParentField.querySelector( '.frm_post_parent_opt_wrapper' ).innerHTML = response.replaceAll( 'REPLACETHISNAME', optName );
7036 - frmDom.autocomplete.initAutocomplete( 'page', postParentField );
7037 - }
7038 - );
7039 - }
4383 + const postParentOpt = postParentField.querySelector( '.frm_autocomplete_value_input' ) || postParentField.querySelector( 'select' );
4384 + const postParentOptName = postParentOpt.getAttribute( 'name' );
7040 4385
7041 - if ( postMenuOrderField ) {
7042 - getActionOption( postMenuOrderField, postType, 'frm_should_use_post_menu_order_option' );
7043 - }
7044 - }
4386 + jQuery.ajax({
4387 + url: ajaxurl,
4388 + method: 'POST',
4389 + data: {
4390 + action: 'frm_get_post_parent_option',
4391 + post_type: postType,
4392 + _wpnonce: frmGlobal.nonce
4393 + },
4394 + success: response => {
4395 + if ( 'string' !== typeof response ) {
4396 + console.error( response );
4397 + return;
4398 + }
7045 4399
7046 - function getActionOption( field, postType, action, successHandler ) {
7047 - const opt = field.querySelector( '.frm_autocomplete_value_input' ) || field.querySelector( 'select' ),
7048 - optName = opt.getAttribute( 'name' );
4400 + // Post type is not hierarchical.
4401 + if ( '0' === response ) {
4402 + postParentField.classList.add( 'frm_hidden' );
4403 + postParentOpt.value = '';
4404 + return;
4405 + }
7049 4406
7050 - jQuery.ajax({
7051 - url: ajaxurl,
7052 - method: 'POST',
7053 - data: {
7054 - action: action,
7055 - post_type: postType,
7056 - _wpnonce: frmGlobal.nonce
7057 - },
7058 - success: response => {
7059 - if ( 'string' !== typeof response ) {
7060 - console.error( response );
7061 - return;
7062 - }
7063 -
7064 - if ( '0' === response ) {
7065 - // This post type does not support this field.
7066 - field.classList.add( 'frm_hidden' );
7067 - field.value = '';
7068 - return;
7069 - }
7070 -
7071 - field.classList.remove( 'frm_hidden' );
7072 -
7073 - if ( 'function' === typeof successHandler ) {
7074 - successHandler( response, optName );
7075 - }
7076 - },
7077 - error: response => console.error( response )
7078 - });
4407 + postParentField.classList.remove( 'frm_hidden' );
4408 + // The replaced string is declared in FrmProFormActionController::ajax_get_post_parent_option() in the pro version.
4409 + postParentField.querySelector( '.frm_post_parent_opt_wrapper' ).innerHTML = response.replaceAll( 'REPLACETHISNAME', postParentOptName );
4410 + initAutocomplete( 'page', postParentField );
4411 + },
4412 + error: response => console.error( response )
4413 + });
4414 + }
7079 4415 }
7080 4416
7081 4417 function addPosttaxRow() {
7082 4418 /*jshint validthis:true */
@@ -7382,11 +4718,11 @@
7382 4718
7383 4719 function setDefaultPostStatus() {
7384 4720 var urlQuery = window.location.search.substring( 1 );
7385 4721 if ( urlQuery.indexOf( 'action=edit' ) === -1 ) {
7386 - document.getElementById( 'post-visibility-display' ).textContent = frm_admin_js.private_label; // eslint-disable-line camelcase
7387 - document.getElementById( 'hidden-post-visibility' ).value = 'private';
7388 - document.getElementById( 'visibility-radio-private' ).checked = true;
4722 + document.getElementById( 'post-visibility-display' ).innerHTML = frm_admin_js.private_label;
4723 + document.getElementById( 'hidden-post-visibility' ).value = 'private';
4724 + document.getElementById( 'visibility-radio-private' ).checked = true;
7389 4725 }
7390 4726 }
7391 4727
7392 4728 /* Customization Panel */
@@ -7442,8 +4778,10 @@
7442 4778 }
7443 4779
7444 4780 if ( rich ) {
7445 4781 wpActiveEditor = elementId;
4782 + send_to_editor( variable );
4783 + return;
7446 4784 }
7447 4785
7448 4786 if ( ! contentBox.length ) {
7449 4787 return false;
@@ -7461,48 +4799,18 @@
7461 4799 form_id: jQuery( 'input[name="id"]' ).val(),
7462 4800 plain_text: p,
7463 4801 nonce: frmGlobal.nonce
7464 4802 },
7465 - elementId: elementId,
7466 4803 success: function( msg ) {
7467 - if ( rich ) {
7468 - let p = document.createElement( 'p' );
7469 - p.innerText = msg;
7470 - send_to_editor( p.innerHTML );
7471 - } else {
7472 - insertContent( contentBox, msg );
7473 - }
4804 + insertContent( contentBox, msg );
7474 4805 }
7475 4806 });
7476 4807 } else {
7477 - variable = maybeAddSanitizeUrlToShortcodeVariable( variable, element, contentBox );
7478 - if ( rich ) {
7479 - send_to_editor( variable );
7480 - } else {
7481 - insertContent( contentBox, variable );
7482 - }
4808 + insertContent( contentBox, variable );
7483 4809 }
7484 4810 return false;
7485 4811 }
7486 4812
7487 - function maybeAddSanitizeUrlToShortcodeVariable( variable, element, contentBox ) {
7488 - if ( 'object' !== typeof element || ! ( element instanceof jQuery ) || 0 !== contentBox[0].id.indexOf( 'success_url_' ) ) {
7489 - return variable;
7490 - }
7491 -
7492 - element = element[0];
7493 - if ( ! element.closest( '#frm-insert-fields-box' ) ) {
7494 - // Only add sanitize_url=1 to field shortcodes.
7495 - return variable;
7496 - }
7497 -
7498 - if ( ! element.parentNode.classList.contains( 'frm_insert_url' ) ) {
7499 - variable = variable.replace( ']', ' sanitize_url=1]' );
7500 - }
7501 -
7502 - return variable;
7503 - }
7504 -
7505 4813 function insertContent( contentBox, variable ) {
7506 4814 if ( document.selection ) {
7507 4815 contentBox[0].focus();
7508 4816 document.selection.createRange().text = variable;
@@ -7571,9 +4879,9 @@
7571 4879
7572 4880 idKey = document.getElementById( idKey );
7573 4881 field = idKey.options[idKey.selectedIndex].value;
7574 4882 code = 'if ' + field + ' ' + is + '="' + text + '"]';
7575 - result.setAttribute( 'data-code', code + frm_admin_js.conditional_text + '[/if ' + field ); // eslint-disable-line camelcase
4883 + result.setAttribute( 'data-code', code + frm_admin_js.conditional_text + '[/if ' + field );
7576 4884 result.innerHTML = '[' + code + '[/if ' + field + ']';
7577 4885 }
7578 4886
7579 4887 function showBuilderModal() {
@@ -7623,9 +4931,9 @@
7623 4931 if ( classes.indexOf( 'frm_close_icon' ) !== -1 ) {
7624 4932 hideShortcodes( box );
7625 4933 } else {
7626 4934 box.style.top = ( pos.top - parentPos.top + 32 ) + 'px';
7627 - box.style.left = ( pos.left - parentPos.left - 280 ) + 'px';
4935 + box.style.left = ( pos.left - parentPos.left - 257 ) + 'px';
7628 4936
7629 4937 jQuery( '.frm_code_list a' ).removeClass( 'frm_noallow' );
7630 4938 if ( input.classList.contains( 'frm_not_email_to' ) ) {
7631 4939 jQuery( '#frm-insert-fields-box .frm_code_list li:not(.show_frm_not_email_to) a' ).addClass( 'frm_noallow' );
@@ -7642,13 +4950,9 @@
7642 4950 moreIcon.className = classes.replace( 'frm_more_horiz_solid_icon', 'frm_close_icon' );
7643 4951 }
7644 4952
7645 4953 if ( shouldFocus !== 'nofocus' ) {
7646 - if ( 'none' !== input.style.display ) {
7647 - input.focus();
7648 - } else {
7649 - jQuery( tinymce.get( input.id ) ).trigger( 'focus' );
7650 - }
4954 + input.focus();
7651 4955 }
7652 4956 }
7653 4957 }
7654 4958
@@ -7668,24 +4972,8 @@
7668 4972 // set fieldsUpdated to 0 to avoid the unsaved changes pop up
7669 4973 fieldsUpdated = 0;
7670 4974 }
7671 4975
7672 - function saveAndReloadSettings() {
7673 - var page, form;
7674 - page = document.getElementById( 'form_settings_page' );
7675 - if ( null !== page ) {
7676 - form = page.querySelector( 'form.frm_form_settings' );
7677 - if ( null !== form ) {
7678 - fieldsUpdated = 0;
7679 - form.submit();
7680 - }
7681 - }
7682 - }
7683 -
7684 - function saveAndReloadFormBuilder() {
7685 - document.getElementById( 'frm_submit_side_top' ).click();
7686 - }
7687 -
7688 4976 function confirmExit( event ) {
7689 4977 if ( fieldsUpdated ) {
7690 4978 event.preventDefault();
7691 4979 event.returnValue = '';
@@ -7692,13 +4980,11 @@
7692 4980 }
7693 4981 }
7694 4982
7695 4983 function bindClickForDialogClose( $modal ) {
7696 - const closeModal = function() {
4984 + jQuery( '.ui-widget-overlay, a.dismiss' ).on( 'click', function() {
7697 4985 $modal.dialog( 'close' );
7698 - };
7699 - jQuery( '.ui-widget-overlay' ).on( 'click', closeModal );
7700 - $modal.on( 'click', 'a.dismiss', closeModal );
4986 + });
7701 4987 }
7702 4988
7703 4989 function triggerNewFormModal( event ) {
7704 4990 var $modal,
@@ -7710,9 +4996,8 @@
7710 4996
7711 4997 dismiss.setAttribute( 'tabindex', -1 );
7712 4998
7713 4999 $modal = initModal( '#frm_new_form_modal', '600px' );
7714 - offsetModalY( $modal, '50px' );
7715 5000 $modal.attr( 'frm-page', 'create' );
7716 5001 $modal.find( '#template-search-input' ).val( '' ).trigger( 'change' );
7717 5002 $modal.dialog( 'open' );
7718 5003
@@ -7717,100 +5002,19 @@
7717 5002 $modal.dialog( 'open' );
7718 5003
7719 5004 dismiss.removeAttribute( 'tabindex' );
7720 5005 bindClickForDialogClose( $modal );
7721 -
7722 - addApplicationsToNewFormModal( $modal.get( 0 ) );
7723 5006 }
7724 5007
7725 - function addApplicationsToNewFormModal( modal ) {
7726 - if ( modal.querySelector( '.frm-ready-made-solution' ) ) {
7727 - // Avoid adding duplicates if the modal is opened multiple times.
7728 - return;
7729 - }
7730 -
7731 - if ( ! frmGlobal.canAccessApplicationDashboard ) {
7732 - // User does not have privileges to see Ready Made Solutions.
7733 - return;
7734 - }
7735 -
7736 - doJsonFetch( 'get_applications_data&view=templates' ).then( addTemplatesOnFetchSuccess );
7737 -
7738 - const categoryList = modal.querySelector( 'ul.frm-categories-list' );
7739 -
7740 - function addTemplatesOnFetchSuccess( data ) {
7741 - data.templates.forEach( addTemplateToCategoryList );
7742 - initSearch( 'template-search-input', 'frm-searchable-template frm-ready-made-solution' );
7743 - }
7744 -
7745 - function addTemplateToCategoryList( template ) {
7746 - categoryList.appendChild( getReadyMadeSolution( template ) );
7747 - }
7748 -
7749 - function getReadyMadeSolution( template ) {
7750 - const image = tag( 'img' );
7751 - const thumbnailFolderUrl = frmGlobal.url + '/images/applications/thumbnails/';
7752 - const filenameToUse = template.hasLiteThumbnail ? template.key + '.png' : 'placeholder.svg';
7753 - image.setAttribute( 'src', thumbnailFolderUrl + filenameToUse );
7754 -
7755 - const imageWrapper = div({ child: image });
7756 - const href = frmGlobal.applicationsUrl + '&triggerViewApplicationModal=1&template=' + template.key;
7757 -
7758 - return tag(
7759 - 'li',
7760 - {
7761 - className: 'frm-searchable-template frm-ready-made-solution frm-selectable',
7762 - data: {
7763 - href: href
7764 - },
7765 - children: [
7766 - imageWrapper,
7767 - div({
7768 - className: 'frm-solution-details',
7769 - children: [
7770 - span({
7771 - className: 'frm-meta-tag',
7772 - text: __( 'Ready Made Solution', 'formidable' )
7773 - }),
7774 - tag( 'h3', template.name ),
7775 - a({
7776 - text: __( 'See all applications', 'formidable' ),
7777 - href: frmGlobal.applicationsUrl
7778 - })
7779 - ]
7780 - }),
7781 - div({
7782 - className: 'frm-hover-icons',
7783 - child: a({
7784 - child: svg({ href: '#frm_plus_icon' }),
7785 - href: href
7786 - })
7787 - })
7788 - ]
7789 - }
7790 - );
7791 - }
7792 - }
7793 -
7794 - function offsetModalY( $modal, amount ) {
7795 - const position = {
7796 - my: 'top',
7797 - at: 'top+' + amount,
7798 - of: window
7799 - };
7800 - $modal.dialog( 'option', 'position', position );
7801 - }
7802 -
7803 5008 /**
7804 5009 * Get the input box for the selected ... icon.
7805 5010 */
7806 5011 function getInputForIcon( moreIcon ) {
7807 5012 var input = moreIcon.nextElementSibling;
7808 -
7809 - while ( input !== null && input.tagName !== 'INPUT' && input.tagName !== 'TEXTAREA' ) {
7810 - input = getInputForIcon( input );
5013 + if ( input !== null && input.tagName !== 'INPUT' && input.tagName !== 'TEXTAREA' ) {
5014 + // Workaround for 1Password.
5015 + input = input.nextElementSibling;
7811 5016 }
7812 -
7813 5017 return input;
7814 5018 }
7815 5019
7816 5020 /**
@@ -7817,13 +5021,11 @@
7817 5021 * Get the ... icon for the selected input box.
7818 5022 */
7819 5023 function getIconForInput( input ) {
7820 5024 var moreIcon = input.previousElementSibling;
7821 -
7822 - while ( moreIcon !== null && moreIcon.tagName !== 'I' && moreIcon.tagName !== 'svg' ) {
7823 - moreIcon = getIconForInput( moreIcon );
5025 + if ( moreIcon !== null && moreIcon.tagName !== 'I' && moreIcon.tagName !== 'svg' ) {
5026 + moreIcon = moreIcon.previousElementSibling;
7824 5027 }
7825 -
7826 5028 return moreIcon;
7827 5029 }
7828 5030
7829 5031 function hideShortcodes( box ) {
@@ -7972,25 +5174,68 @@
7972 5174 jQuery( '.frmids, .frmkeys' ).removeClass( 'current' );
7973 5175 jQuery( '.' + switchTo ).addClass( 'current' );
7974 5176 }
7975 5177
7976 - function onActionLoaded( event ) {
7977 - const settings = event.target.closest( '.frm_form_action_settings' );
7978 - if ( settings && ( settings.classList.contains( 'frm_single_email_settings' ) || settings.classList.contains( 'frm_single_on_submit_settings' ) ) ) {
7979 - initWysiwygOnActionLoaded( settings );
5178 + /* Styling */
5179 +
5180 + //function to append a new theme stylesheet with the new style changes
5181 + function updateUICSS( locStr ) {
5182 + var $cssLink, $link;
5183 +
5184 + if ( locStr == -1 ) {
5185 + jQuery( 'link.ui-theme' ).remove();
5186 + return false;
7980 5187 }
5188 +
5189 + $cssLink = jQuery( '<link href="' + locStr + '" type="text/css" rel="Stylesheet" class="ui-theme" />' );
5190 + jQuery( 'head' ).append( $cssLink );
5191 +
5192 + $link = jQuery( 'link.ui-theme' );
5193 + if ( $link.length > 1 ) {
5194 + $link.first().remove();
5195 + }
7981 5196 }
7982 5197
7983 - function initWysiwygOnActionLoaded( settings ) {
7984 - const wysiwyg = settings.querySelector( '.wp-editor-area' );
7985 - if ( wysiwyg ) {
7986 - frmDom.wysiwyg.init(
7987 - wysiwyg,
7988 - { height: 160, addFocusEvents: true }
7989 - );
5198 + function setPosClass() {
5199 + /*jshint validthis:true */
5200 + var value = this.value;
5201 + if ( value === 'none' ) {
5202 + value = 'top';
5203 + } else if ( value === 'no_label' ) {
5204 + value = 'none';
7990 5205 }
5206 + jQuery( '.frm_pos_container' ).removeClass( 'frm_top_container frm_left_container frm_right_container frm_none_container frm_inside_container' ).addClass( 'frm_' + value + '_container' );
7991 5207 }
7992 5208
5209 + function collapseAllSections() {
5210 + jQuery( '.control-section.accordion-section.open' ).removeClass( 'open' );
5211 + }
5212 +
5213 + function textSquishCheck() {
5214 + var size = document.getElementById( 'frm_field_font_size' ).value.replace( /\D/g, '' );
5215 + var height = document.getElementById( 'frm_field_height' ).value.replace( /\D/g, '' );
5216 + var paddingEntered = document.getElementById( 'frm_field_pad' ).value.split( ' ' );
5217 + var paddingCount = paddingEntered.length;
5218 +
5219 + // If too many or too few padding entries, leave now
5220 + if ( paddingCount === 0 || paddingCount > 4 || height === '' ) {
5221 + return;
5222 + }
5223 +
5224 + // Get the top and bottom padding from entered values
5225 + var paddingTop = paddingEntered[0].replace( /\D/g, '' );
5226 + var paddingBottom = paddingTop;
5227 + if ( paddingCount >= 3 ) {
5228 + paddingBottom = paddingEntered[2].replace( /\D/g, '' );
5229 + }
5230 +
5231 + // Check if there is enough space for text
5232 + var textSpace = height - size - paddingTop - paddingBottom - 3;
5233 + if ( textSpace < 0 ) {
5234 + infoModal( frm_admin_js.css_invalid_size );
5235 + }
5236 + }
5237 +
7993 5238 /* Global settings page */
7994 5239 function loadSettingsTab( anchor ) {
7995 5240 var holder = anchor.replace( '#', '' );
7996 5241 var holderContainer = jQuery( '.frm_' + holder + '_ajax' );
@@ -8110,9 +5355,9 @@
8110 5355 * Imports a single form from the import queue.
8111 5356 */
8112 5357 function importForm( $processSettings ) {
8113 5358 var formID = s.importQueue[0],
8114 - provider = jQuery( '#welcome-panel' ).find( 'input[name="slug"]' ).val(),
5359 + provider = $processSettings.closest( '.welcome-panel-content' ).find( 'input[name="slug"]' ).val(),
8115 5360 data = {
8116 5361 action: 'frm_import_' + provider,
8117 5362 form_id: formID,
8118 5363 nonce: frmGlobal.nonce
@@ -8204,34 +5449,8 @@
8204 5449 jQuery( '.show_csv' ).fadeOut();
8205 5450 }
8206 5451 }
8207 5452
8208 - function getExportOption() {
8209 - const exportFormatSelect = document.querySelector( 'select[name="format"]' );
8210 - if ( exportFormatSelect ) {
8211 - return exportFormatSelect.value;
8212 - } else {
8213 - return '';
8214 - }
8215 - }
8216 -
8217 - function exportTypeChanged( event ) {
8218 - const value = event.target.value;
8219 - showOrHideRepeaters( value );
8220 - checkExportTypes.call( event.target );
8221 - checkSelectedAllFormsCheckbox( value );
8222 - }
8223 -
8224 - function checkSelectedAllFormsCheckbox( exportType ) {
8225 - const selectAllCheckbox = document.getElementById( 'frm-export-select-all' );
8226 - if ( exportType === 'csv' ) {
8227 - selectAllCheckbox.checked = false;
8228 - selectAllCheckbox.disabled = true;
8229 - } else {
8230 - selectAllCheckbox.disabled = false;
8231 - }
8232 - }
8233 -
8234 5453 function checkExportTypes() {
8235 5454 /*jshint validthis:true */
8236 5455 var $dropdown = jQuery( this );
8237 5456 var $selected = $dropdown.find( ':selected' );
@@ -8266,34 +5485,10 @@
8266 5485 } else {
8267 5486 exportField.prop( 'multiple', true );
8268 5487 exportField.prop( 'disabled', false );
8269 5488 }
8270 - $dropdown.trigger( 'change' );
8271 5489 }
8272 5490
8273 - function showOrHideRepeaters( exportOption ) {
8274 - if ( exportOption === '' ) {
8275 - return;
8276 - }
8277 -
8278 - const repeaters = document.querySelectorAll( '.frm-is-repeater' );
8279 - if ( ! repeaters.length ) {
8280 - return;
8281 - }
8282 -
8283 - if ( exportOption === 'csv' ) {
8284 - repeaters.forEach( form => {
8285 - form.classList.remove( 'frm_hidden' );
8286 - });
8287 - } else {
8288 - repeaters.forEach( form => {
8289 - form.classList.add( 'frm_hidden' );
8290 - });
8291 - }
8292 -
8293 - searchContent.call( document.querySelector( '.frm-auto-search' ) );
8294 - }
8295 -
8296 5491 function preventMultipleExport() {
8297 5492 var type = jQuery( 'select[name=format]' ),
8298 5493 selected = type.find( ':selected' ),
8299 5494 count = selected.data( 'count' ),
@@ -8311,10 +5506,50 @@
8311 5506 exportField.prop( 'disabled', false );
8312 5507 }
8313 5508 }
8314 5509
5510 + function multiselectAccessibility() {
5511 + jQuery( '.multiselect-container' ).find( 'input[type="checkbox"]' ).each( function() {
5512 + var checkbox = jQuery( this );
5513 + checkbox.closest( 'a' ).attr(
5514 + 'aria-describedby',
5515 + checkbox.is( ':checked' ) ? 'frm_press_space_checked' : 'frm_press_space_unchecked'
5516 + );
5517 + });
5518 + }
5519 +
8315 5520 function initiateMultiselect() {
8316 - jQuery( '.frm_multiselect' ).hide().each( frmDom.bootstrap.multiselect.init );
5521 + jQuery( '.frm_multiselect' ).hide().each( function() {
5522 + var $select = jQuery( this ),
5523 + id = $select.is( '[id]' ) ? $select.attr( 'id' ).replace( '[]', '' ) : false,
5524 + labelledBy = id ? jQuery( '#for_' + id ) : false;
5525 + labelledBy = id && labelledBy.length ? 'aria-labelledby="' + labelledBy.attr( 'id' ) + '"' : '';
5526 + $select.multiselect({
5527 + templates: {
5528 + ul: '<ul class="multiselect-container frm-dropdown-menu"></ul>',
5529 + li: '<li><a tabindex="0"><label></label></a></li>',
5530 + button: '<button type="button" class="multiselect dropdown-toggle" data-toggle="dropdown" aria-describedby="frm_multiselect_button" ' + labelledBy + '><span class="multiselect-selected-text"></span> <b class="caret"></b></button>'
5531 + },
5532 + buttonContainer: '<div class="btn-group frm-btn-group dropdown" />',
5533 + nonSelectedText: '',
5534 + onDropdownShown: function( event ) {
5535 + var action = jQuery( event.currentTarget.closest( '.frm_form_action_settings, #frm-show-fields' ) );
5536 + if ( action.length ) {
5537 + jQuery( '#wpcontent' ).on( 'click', function() {
5538 + if ( jQuery( '.multiselect-container.frm-dropdown-menu' ).is( ':visible' ) ) {
5539 + jQuery( event.currentTarget ).removeClass( 'open' );
5540 + }
5541 + });
5542 + }
5543 +
5544 + multiselectAccessibility();
5545 + },
5546 + onChange: function( element, option ) {
5547 + multiselectAccessibility();
5548 + $select.trigger( 'frm-multiselect-changed', element, option );
5549 + }
5550 + });
5551 + });
8317 5552 }
8318 5553
8319 5554 /* Addons page */
8320 5555 function installMultipleAddons( e ) {
@@ -8332,16 +5567,14 @@
8332 5567 installOrActivate( this, 'frm_install_addon' );
8333 5568 }
8334 5569
8335 5570 function installOrActivate( clicked, action ) {
8336 - let button, plugin, el, message;
8337 -
8338 5571 // Remove any leftover error messages, output an icon and get the plugin basename that needs to be activated.
8339 5572 jQuery( '.frm-addon-error' ).remove();
8340 - button = jQuery( clicked );
8341 - plugin = button.attr( 'rel' );
8342 - el = button.parent();
8343 - message = el.parent().find( '.addon-status-label' );
5573 + var button = jQuery( clicked );
5574 + var plugin = button.attr( 'rel' );
5575 + var el = button.parent();
5576 + var message = el.parent().find( '.addon-status-label' );
8344 5577
8345 5578 button.addClass( 'frm_loading_button' );
8346 5579
8347 5580 // Process the Ajax to perform the activation.
@@ -8356,24 +5589,16 @@
8356 5589 nonce: frmGlobal.nonce,
8357 5590 plugin: plugin
8358 5591 },
8359 5592 success: function( response ) {
8360 - let saveAndReload;
5593 + var error = extractErrorFromAddOnResponse( response );
8361 5594
8362 - if ( 'string' !== typeof response && 'string' === typeof response.message ) {
8363 - if ( 'undefined' !== typeof response.saveAndReload ) {
8364 - saveAndReload = response.saveAndReload;
8365 - }
8366 - response = response.message;
8367 - }
8368 -
8369 - const error = extractErrorFromAddOnResponse( response );
8370 5595 if ( error ) {
8371 5596 addonError( error, el, button );
8372 5597 return;
8373 5598 }
8374 5599
8375 - afterAddonInstall( response, button, message, el, saveAndReload );
5600 + afterAddonInstall( response, button, message, el );
8376 5601 },
8377 5602 error: function() {
8378 5603 button.removeClass( 'frm_loading_button' );
8379 5604 }
@@ -8384,11 +5609,11 @@
8384 5609 // Prevent the default action, let the user know we are attempting to install again and go with it.
8385 5610 e.preventDefault();
8386 5611
8387 5612 // Now let's make another Ajax request once the user has submitted their credentials.
8388 - const proceed = jQuery( this );
8389 - const el = proceed.parent().parent();
8390 - const plugin = proceed.attr( 'rel' );
5613 + var proceed = jQuery( this ),
5614 + el = proceed.parent().parent(),
5615 + plugin = proceed.attr( 'rel' );
8391 5616
8392 5617 proceed.addClass( 'frm_loading_button' );
8393 5618
8394 5619 jQuery.ajax({
@@ -8398,9 +5623,9 @@
8398 5623 cache: false,
8399 5624 dataType: 'json',
8400 5625 data: {
8401 5626 action: 'frm_install_addon',
8402 - nonce: frm_admin_js.nonce, // eslint-disable-line camelcase
5627 + nonce: frm_admin_js.nonce,
8403 5628 plugin: plugin,
8404 5629 hostname: el.find( '#hostname' ).val(),
8405 5630 username: el.find( '#username' ).val(),
8406 5631 password: el.find( '#password' ).val()
@@ -8405,9 +5630,10 @@
8405 5630 username: el.find( '#username' ).val(),
8406 5631 password: el.find( '#password' ).val()
8407 5632 },
8408 5633 success: function( response ) {
8409 - const error = extractErrorFromAddOnResponse( response );
5634 + var error = extractErrorFromAddOnResponse( response );
5635 +
8410 5636 if ( error ) {
8411 5637 addonError( error, el, proceed );
8412 5638 return;
8413 5639 }
@@ -8419,27 +5645,14 @@
8419 5645 }
8420 5646 });
8421 5647 }
8422 5648
8423 - function afterAddonInstall( response, button, message, el, saveAndReload ) {
8424 - const addonStatuses = document.querySelectorAll( '.frm-addon-status' );
8425 - addonStatuses.forEach(
8426 - addonStatus => {
8427 - addonStatus.textContent = response;
8428 - addonStatus.style.display = 'block';
8429 - }
8430 - );
8431 -
5649 + function afterAddonInstall( response, button, message, el ) {
8432 5650 // The Ajax request was successful, so let's update the output.
8433 - button.css({ opacity: '0' });
8434 - message.text( frm_admin_js.active ); // eslint-disable-line camelcase
8435 -
8436 - document.querySelectorAll( '.frm-oneclick' ).forEach(
8437 - oneClick => {
8438 - oneClick.style.display = 'none';
8439 - }
8440 - );
8441 -
5651 + button.css({ 'opacity': '0' });
5652 + message.text( frm_admin_js.active );
5653 + jQuery( '#frm-oneclick' ).hide();
5654 + jQuery( '#frm-addon-status' ).text( response ).show();
8442 5655 jQuery( '#frm_upgrade_modal h2' ).hide();
8443 5656 jQuery( '#frm_upgrade_modal .frm_lock_icon' ).addClass( 'frm_lock_open_icon' );
8444 5657 jQuery( '#frm_upgrade_modal .frm_lock_icon use' ).attr( 'xlink:href', '#frm_lock_open_icon' );
8445 5658
@@ -8447,56 +5660,17 @@
8447 5660 el.parent().removeClass( 'frm-addon-not-installed frm-addon-installed' ).addClass( 'frm-addon-active' );
8448 5661 button.removeClass( 'frm_loading_button' );
8449 5662
8450 5663 // Maybe refresh import and SMTP pages
8451 - const refreshPage = document.querySelectorAll( '.frm-admin-page-import, #frm-admin-smtp, #frm-welcome' );
5664 + var refreshPage = document.querySelectorAll( '.frm-admin-page-import, #frm-admin-smtp, #frm-welcome' );
8452 5665 if ( refreshPage.length > 0 ) {
8453 5666 window.location.reload();
8454 - return;
8455 5667 }
8456 -
8457 - if ([ 'settings', 'form_builder' ].includes( saveAndReload ) ) {
8458 - addonStatuses.forEach(
8459 - addonStatus => {
8460 - const inModal = null !== addonStatus.closest( '#frm_upgrade_modal' );
8461 - addonStatus.appendChild( getSaveAndReloadSettingsOptions( saveAndReload, inModal ) );
8462 - }
8463 - );
8464 - }
8465 5668 }
8466 5669
8467 - function getSaveAndReloadSettingsOptions( saveAndReload, inModal ) {
8468 - const className = 'frm-save-and-reload-options';
8469 - const children = [ saveAndReloadSettingsButton( saveAndReload ) ];
8470 - if ( inModal ) {
8471 - children.push( closePopupButton() );
8472 - }
8473 - return div({ className, children });
8474 - }
5670 + function extractErrorFromAddOnResponse( response ) {
5671 + var $message, text;
8475 5672
8476 - function saveAndReloadSettingsButton( saveAndReload ) {
8477 - var button = document.createElement( 'button' );
8478 - button.classList.add( 'frm-save-and-reload', 'button', 'button-primary', 'frm-button-primary' );
8479 - button.textContent = __( 'Save and Reload', 'formidable' );
8480 - button.addEventListener( 'click', () => {
8481 - if ( saveAndReload === 'form_builder' ) {
8482 - saveAndReloadFormBuilder();
8483 - } else if ( saveAndReload === 'settings' ) {
8484 - saveAndReloadSettings();
8485 - }
8486 - });
8487 - return button;
8488 - }
8489 -
8490 - function closePopupButton() {
8491 - var a = document.createElement( 'a' );
8492 - a.setAttribute( 'href', '#' );
8493 - a.classList.add( 'button', 'button-secondary', 'frm-button-secondary', 'dismiss' );
8494 - a.textContent = __( 'Close', 'formidable' );
8495 - return a;
8496 - }
8497 -
8498 - function extractErrorFromAddOnResponse( response ) {
8499 5673 if ( typeof response !== 'string' ) {
8500 5674 if ( typeof response.success !== 'undefined' && response.success ) {
8501 5675 return false;
8502 5676 }
@@ -8553,19 +5727,8 @@
8553 5727
8554 5728 jQuery( document ).on( 'click', '.frm-trigger-new-form-modal', triggerNewFormModal );
8555 5729 $modal = initModal( '#frm_new_form_modal', '600px' );
8556 5730
8557 - if ( false === $modal ) {
8558 - return;
8559 - }
8560 -
8561 - setTimeout(
8562 - function() {
8563 - $modal.get( 0 ).querySelector( '.postbox' ).style.display = 'block'; // Fixes pro issue #3508, prevent a conflict that hides the postbox in modal.
8564 - },
8565 - 0
8566 - );
8567 -
8568 5731 installFormTrigger = document.createElement( 'a' );
8569 5732 installFormTrigger.classList.add( 'frm-install-template', 'frm_hidden' );
8570 5733 document.body.appendChild( installFormTrigger );
8571 5734
@@ -8582,10 +5745,10 @@
8582 5745
8583 5746 document.getElementById( 'frm_template_name' ).value = oldName;
8584 5747 document.getElementById( 'frm_link' ).value = this.attributes.rel.value;
8585 5748 document.getElementById( 'frm_action_type' ).value = 'frm_install_template';
8586 - nameLabel.textContent = nameLabel.getAttribute( 'data-form' );
8587 - descLabel.textContent = descLabel.getAttribute( 'data-form' );
5749 + nameLabel.innerHTML = nameLabel.getAttribute( 'data-form' );
5750 + descLabel.innerHTML = descLabel.getAttribute( 'data-form' );
8588 5751 $modal.dialog( 'open' );
8589 5752 });
8590 5753
8591 5754 jQuery( document ).on( 'submit', '#frm-new-template', installTemplate );
@@ -8614,12 +5777,8 @@
8614 5777 $modal.attr( 'frm-page', 'preview' );
8615 5778 activeHoverIcons = jQuery( this ).closest( '.frm-hover-icons' );
8616 5779 });
8617 5780
8618 - jQuery( document ).on( 'click', 'li.frm-ready-made-solution[data-href]', function() {
8619 - window.location = this.getAttribute( 'data-href' );
8620 - });
8621 -
8622 5781 jQuery( document ).on( 'click', 'li .frm-hover-icons .frm-create-form', function( event ) {
8623 5782 var $li, name, link, action;
8624 5783
8625 5784 event.preventDefault();
@@ -8696,9 +5855,10 @@
8696 5855 dataType: 'json',
8697 5856 url: formContainer.getAttribute( 'data-url' ),
8698 5857 success: function( json ) {
8699 5858 var form = json.renderedHtml;
8700 - form = form.replace( /<link\b[^>]*(formidableforms.css|action=frmpro_css)[^>]*>/gi, '' );
5859 + form = form.replace( /<script\b[^<]*(community.formidableforms.com\/wp-includes\/js\/jquery\/jquery)[^<]*><\/script>/gi, '' );
5860 + form = form.replace( /<link\b[^>]*(formidableforms.css)[^>]*>/gi, '' );
8701 5861 formContainer.innerHTML = form;
8702 5862 }
8703 5863 });
8704 5864
@@ -8734,9 +5894,9 @@
8734 5894 .closest( '.accordion-section-content' ).css( 'overflow', 'visible' )
8735 5895 .closest( '.accordion-section' ).css( 'z-index', 1 );
8736 5896 });
8737 5897
8738 - jQuery( document ).on( 'click', '#frm_new_form_modal #frm-template-drop + .frm-dropdown-menu .frm-build-template', function() {
5898 + jQuery( document ).on( 'click', '#frm_new_form_modal #frm-template-drop + ul .frm-build-template', function() {
8739 5899 var name = this.getAttribute( 'data-fullname' ),
8740 5900 link = this.getAttribute( 'data-formid' ),
8741 5901 action = 'frm_build_template';
8742 5902 transitionToAddDetails( $modal, name, link, action );
@@ -8838,12 +5998,8 @@
8838 5998 if ( typeof response.data !== 'undefined' && typeof response.data.url !== 'undefined' ) {
8839 5999 installFormTrigger.setAttribute( 'rel', response.data.url );
8840 6000 installFormTrigger.click();
8841 6001 $modal.attr( 'frm-page', 'details' );
8842 -
8843 - const hookName = 'frm_new_form_modal_form';
8844 - wp.hooks.doAction( hookName, $modal );
8845 -
8846 6002 document.getElementById( 'frm_action_type' ).value = 'frm_install_template';
8847 6003
8848 6004 if ( typeof response.data.urlByKey !== 'undefined' ) {
8849 6005 updateTemplateModalFreeUrls( response.data.urlByKey );
@@ -8871,8 +6027,28 @@
8871 6027 jQuery( '#frm_code_from_email_options, #frm_code_from_email_error' ).addClass( 'frm_hidden' );
8872 6028 document.getElementById( 'frm-add-my-email-address' ).click();
8873 6029 });
8874 6030
6031 + jQuery( document ).on( 'frmAfterSearch', '#frm_new_form_modal #template-search-input', function() {
6032 + var categories = $modal.get( 0 ).querySelector( '.frm-categories-list' ).children,
6033 + categoryIndex,
6034 + category,
6035 + searchableTemplates,
6036 + count;
6037 +
6038 + for ( categoryIndex in categories ) {
6039 + if ( isNaN( categoryIndex ) ) {
6040 + continue;
6041 + }
6042 +
6043 + category = categories[ categoryIndex ];
6044 + searchableTemplates = category.querySelectorAll( '.frm-searchable-template:not(.frm_hidden)' );
6045 + count = searchableTemplates.length;
6046 + jQuery( category ).toggleClass( 'frm_hidden', this.value !== '' && ! count );
6047 + setTemplateCount( category, searchableTemplates );
6048 + }
6049 + });
6050 +
8875 6051 jQuery( document ).on( 'click', '#frm_new_form_modal .frm-modal-back, #frm_new_form_modal .frm_modal_footer .frm-modal-cancel, #frm_new_form_modal .frm-back-to-all-templates', function( event ) {
8876 6052 document.getElementById( 'frm-create-title' ).removeAttribute( 'frm-type' );
8877 6053 $modal.attr( 'frm-page', 'create' );
8878 6054 });
@@ -8907,53 +6083,12 @@
8907 6083
8908 6084 if ( firstLockedTemplate.length ) {
8909 6085 showFreeTemplatesForm( firstLockedTemplate );
8910 6086 }
8911 -
8912 - // Hides the back button in the Free Template Modal and shows it when the cancel button is clicked
8913 - $modalBackButton = $modal.find( '.frm-modal-back' );
8914 - $modalBackButton.hide();
8915 - $modal.find( '.frm-modal-cancel' ).on( 'click', ( event ) => {
8916 - $modalBackButton.show();
8917 - $modal.dialog( 'close' );
8918 - });
8919 6087 }
8920 6088 }
8921 -
8922 - initSearch( 'template-search-input', 'control-section accordion-section' );
8923 6089 }
8924 6090
8925 - function initSearch( inputID, itemClass ) {
8926 - const searchInput = document.getElementById( inputID );
8927 -
8928 - if ( itemClass === 'control-section accordion-section' ) {
8929 - itemClass = 'frm-selectable frm-searchable-template';
8930 -
8931 - const handleTemplateSearch = () => {
8932 - document.querySelectorAll( '.control-section.accordion-section' ).forEach( category => {
8933 - const found = category.querySelector( '.frm-selectable.frm-searchable-template:not(.frm_hidden)' ) || ( searchInput.value === '' && category.querySelector( '#frm-template-drop' ) );
8934 - if ( found ) {
8935 - setTemplateCount( category );
8936 - }
8937 - category.classList.toggle( 'frm_hidden', ! found );
8938 - });
8939 - };
8940 -
8941 - frmDom.search.init( searchInput, itemClass, { handleSearchResult: handleTemplateSearch });
8942 -
8943 - } else {
8944 - if ( itemClass === 'frm-searchable-template frm-ready-made-solution' ) {
8945 - Array.from( document.getElementsByClassName( itemClass ) ).forEach( item => {
8946 - let innerText = '';
8947 - innerText = item.querySelector( 'h3' ).innerText;
8948 - item.setAttribute( 'frm-search-text', innerText.toLowerCase() );
8949 - });
8950 - }
8951 - frmDom.search.init( searchInput, itemClass );
8952 - }
8953 -
8954 - }
8955 -
8956 6091 function updateTemplateModalFreeUrls( urlByKey ) {
8957 6092 jQuery( '#frm_new_form_modal' ).find( '.frm-selectable[data-key]' ).each( function() {
8958 6093 var $template = jQuery( this ),
8959 6094 key = $template.attr( 'data-key' );
@@ -8974,19 +6109,14 @@
8974 6109 templateNameInput.value = name;
8975 6110 document.getElementById( 'frm_link' ).value = link;
8976 6111 document.getElementById( 'frm_action_type' ).value = action;
8977 6112 nameLabel.textContent = nameLabel.getAttribute( 'data-' + type );
8978 - if ( descLabel !== null ) {
8979 - descLabel.textContent = descLabel.getAttribute( 'data-' + type );
8980 - }
6113 + descLabel.textContent = descLabel.getAttribute( 'data-' + type );
8981 6114
8982 6115 document.getElementById( 'frm-create-title' ).setAttribute( 'frm-type', type );
8983 6116
8984 6117 $modal.attr( 'frm-page', 'details' );
8985 6118
8986 - const hookName = 'frm_new_form_modal_form';
8987 - wp.hooks.doAction( hookName, $modal );
8988 -
8989 6119 if ( '' === name ) {
8990 6120 templateNameInput.focus();
8991 6121 }
8992 6122 }
@@ -8992,9 +6122,9 @@
8992 6122 }
8993 6123
8994 6124 function getStrippedTemplateName( $li ) {
8995 6125 var $clone = $li.find( 'h3' ).clone();
8996 - $clone.find( 'svg, .frm-plan-required-tag, .frm-new-pill' ).remove();
6126 + $clone.find( 'svg, .frm-plan-required-tag' ).remove();
8997 6127 return $clone.html().trim();
8998 6128 }
8999 6129
9000 6130 function setTemplateCount( category, searchableTemplates ) {
@@ -9026,11 +6156,96 @@
9026 6156 }
9027 6157 }
9028 6158
9029 6159 function initSelectionAutocomplete() {
9030 - frmDom.autocomplete.initSelectionAutocomplete();
6160 + if ( jQuery.fn.autocomplete ) {
6161 + initAutocomplete( 'page' );
6162 + initAutocomplete( 'user' );
6163 + }
9031 6164 }
9032 6165
6166 + /**
6167 + * Init autocomplete.
6168 + *
6169 + * @since 4.10.01 Add container param to init autocomplete elements inside an element.
6170 + *
6171 + * @param {String} type Type of data. Accepts `page` or `user`.
6172 + * @param {String|Object} container Container class or element. Default is null.
6173 + */
6174 + function initAutocomplete( type, container ) {
6175 + const basedUrlParams = '?action=frm_' + type + '_search&nonce=' + frmGlobal.nonce;
6176 + const elements = ! container ? jQuery( '.frm-' + type + '-search' ) : jQuery( container ).find( '.frm-' + type + '-search' );
6177 +
6178 + elements.each( function() {
6179 + let urlParams = basedUrlParams;
6180 + const element = jQuery( this );
6181 +
6182 + // Check if a custom post type is specific.
6183 + if ( element.attr( 'data-post-type' ) ) {
6184 + urlParams += '&post_type=' + element.attr( 'data-post-type' );
6185 + }
6186 + element.autocomplete({
6187 + delay: 100,
6188 + minLength: 0,
6189 + source: ajaxurl + urlParams,
6190 + change: autoCompleteSelectBlank,
6191 + select: autoCompleteSelectFromResults,
6192 + focus: autoCompleteFocus,
6193 + position: {
6194 + my: 'left top',
6195 + at: 'left bottom',
6196 + collision: 'flip'
6197 + },
6198 + response: function( event, ui ) {
6199 + if ( ! ui.content.length ) {
6200 + var noResult = { value: '', label: frm_admin_js.no_items_found };
6201 + ui.content.push( noResult );
6202 + }
6203 + },
6204 + create: function() {
6205 + var $container = jQuery( this ).parent();
6206 +
6207 + if ( $container.length === 0 ) {
6208 + $container = 'body';
6209 + }
6210 +
6211 + jQuery( this ).autocomplete( 'option', 'appendTo', $container );
6212 + }
6213 + })
6214 + .on( 'focus', function() {
6215 + // Show options on click to make it work more like a dropdown.
6216 + if ( this.value === '' || this.nextElementSibling.value < 1 ) {
6217 + jQuery( this ).autocomplete( 'search', this.value );
6218 + }
6219 + });
6220 + });
6221 + }
6222 +
6223 + /**
6224 + * Prevent the value from changing when using keyboard to scroll.
6225 + */
6226 + function autoCompleteFocus() {
6227 + return false;
6228 + }
6229 +
6230 + function autoCompleteSelectBlank( e, ui ) {
6231 + if ( ui.item === null ) {
6232 + this.nextElementSibling.value = '';
6233 + }
6234 + }
6235 +
6236 + function autoCompleteSelectFromResults( e, ui ) {
6237 + e.preventDefault();
6238 +
6239 + if ( ui.item.value === '' ) {
6240 + this.value = '';
6241 + } else {
6242 + this.value = ui.item.label;
6243 + }
6244 +
6245 + this.nextElementSibling.value = ui.item.value;
6246 + }
6247 +
9033 6248 function nextInstallStep( thisStep ) {
9034 6249 thisStep.classList.add( 'frm_grey' );
9035 6250 thisStep.nextElementSibling.classList.remove( 'frm_grey' );
9036 6251 }
@@ -9075,14 +6290,15 @@
9075 6290 installNewForm( this, action, button );
9076 6291 }
9077 6292
9078 6293 function installNewForm( form, action, button ) {
9079 - const formData = formToData( form );
9080 - const formName = formData.template_name;
9081 - const formDesc = formData.template_desc;
9082 - const link = form.elements.link.value;
6294 + var data, redirect, href, showError,
6295 + formData = formToData( form ),
6296 + formName = formData.template_name,
6297 + formDesc = formData.template_desc,
6298 + link = form.elements.link.value;
9083 6299
9084 - let data = {
6300 + data = {
9085 6301 action: action,
9086 6302 xml: link,
9087 6303 name: formName,
9088 6304 desc: formDesc,
@@ -9088,20 +6304,15 @@
9088 6304 desc: formDesc,
9089 6305 form: JSON.stringify( formData ),
9090 6306 nonce: frmGlobal.nonce
9091 6307 };
9092 -
9093 - const hookName = 'frm_before_install_new_form';
9094 - const filterArgs = { formData };
9095 - data = wp.hooks.applyFilters( hookName, data, filterArgs );
9096 -
9097 6308 postAjax( data, function( response ) {
9098 - if ( typeof response.redirect !== 'undefined' ) {
9099 - const redirect = response.redirect;
6309 + redirect = response.redirect;
6310 + if ( typeof redirect !== 'undefined' ) {
9100 6311 if ( typeof form.elements.redirect === 'undefined' ) {
9101 6312 window.location = redirect;
9102 6313 } else {
9103 - const href = document.getElementById( 'frm-redirect-link' );
6314 + href = document.getElementById( 'frm-redirect-link' );
9104 6315 if ( typeof link !== 'undefined' && href !== null ) {
9105 6316 // Show the next installation step.
9106 6317 href.setAttribute( 'href', redirect );
9107 6318 href.classList.remove( 'frm_grey', 'disabled' );
@@ -9112,10 +6323,14 @@
9112 6323 } else {
9113 6324 jQuery( '.spinner' ).css( 'visibility', 'hidden' );
9114 6325
9115 6326 // Show response.message
9116 - if ( 'string' === typeof response.message ) {
9117 - showInstallFormErrorModal( response.message );
6327 + if ( response.message && typeof form.elements.show_response !== 'undefined' ) {
6328 + showError = document.getElementById( form.elements.show_response.value );
6329 + if ( showError !== null ) {
6330 + showError.innerHTML = response.message;
6331 + showError.classList.remove( 'frm_hidden' );
6332 + }
9118 6333 }
9119 6334 }
9120 6335 button.classList.remove( 'frm_loading_button' );
9121 6336 });
@@ -9120,28 +6335,8 @@
9120 6335 button.classList.remove( 'frm_loading_button' );
9121 6336 });
9122 6337 }
9123 6338
9124 - function showInstallFormErrorModal( message ) {
9125 - const modalContent = div( message );
9126 - modalContent.style.padding = '20px 40px';
9127 - const modal = frmDom.modal.maybeCreateModal(
9128 - 'frmInstallFormErrorModal',
9129 - {
9130 - title: __( 'Unable to install template', 'formidable' ),
9131 - content: modalContent
9132 - }
9133 - );
9134 - modal.classList.add( 'frm_common_modal' );
9135 - }
9136 -
9137 - function handleCaptchaTypeChange( e ) {
9138 - const thresholdContainer = document.getElementById( 'frm_captcha_threshold_container' );
9139 - if ( thresholdContainer ) {
9140 - thresholdContainer.classList.toggle( 'frm_hidden', 'v3' !== e.target.value );
9141 - }
9142 - }
9143 -
9144 6339 function trashTemplate( e ) {
9145 6340 /*jshint validthis:true */
9146 6341 var id = this.getAttribute( 'data-id' );
9147 6342 e.preventDefault();
@@ -9180,19 +6375,13 @@
9180 6375 }
9181 6376
9182 6377 for ( i = 0; i < items.length; i++ ) {
9183 6378 var innerText = items[i].innerText.toLowerCase();
9184 -
9185 - const itemCanBeShown = ! ( getExportOption() === 'xml' && items[i].classList.contains( 'frm-is-repeater' ) );
9186 6379 if ( searchText === '' ) {
9187 - if ( itemCanBeShown ) {
9188 - items[i].classList.remove( 'frm_hidden' );
9189 - }
6380 + items[i].classList.remove( 'frm_hidden' );
9190 6381 items[i].classList.remove( 'frm-search-result' );
9191 6382 } else if ( ( regEx && new RegExp( searchText ).test( innerText ) ) || innerText.indexOf( searchText ) >= 0 ) {
9192 - if ( itemCanBeShown ) {
9193 - items[i].classList.remove( 'frm_hidden' );
9194 - }
6383 + items[i].classList.remove( 'frm_hidden' );
9195 6384 items[i].classList.add( 'frm-search-result' );
9196 6385 } else {
9197 6386 items[i].classList.add( 'frm_hidden' );
9198 6387 items[i].classList.remove( 'frm-search-result' );
@@ -9229,12 +6418,12 @@
9229 6418 element.dispatchEvent( evt );
9230 6419 }
9231 6420
9232 6421 function postAjax( data, success ) {
9233 - let response;
6422 + var response, params,
6423 + xmlHttp = new XMLHttpRequest();
9234 6424
9235 - const xmlHttp = new XMLHttpRequest();
9236 - const params = typeof data === 'string' ? data : Object.keys( data ).map(
6425 + params = typeof data === 'string' ? data : Object.keys( data ).map(
9237 6426 function( k ) {
9238 6427 return encodeURIComponent( k ) + '=' + encodeURIComponent( data[k]);
9239 6428 }
9240 6429 ).join( '&' );
@@ -9270,10 +6459,10 @@
9270 6459 jQuery( classes ).css( 'visibility', 'visible' );
9271 6460 }
9272 6461
9273 6462 function initModal( id, width ) {
9274 - const $info = jQuery( id );
9275 - if ( ! $info.length ) {
6463 + var $info = jQuery( id );
6464 + if ( $info.length < 1 ) {
9276 6465 return false;
9277 6466 }
9278 6467
9279 6468 if ( typeof width === 'undefined' ) {
@@ -9279,9 +6468,9 @@
9279 6468 if ( typeof width === 'undefined' ) {
9280 6469 width = '550px';
9281 6470 }
9282 6471
9283 - const dialogArgs = {
6472 + $info.dialog({
9284 6473 dialogClass: 'frm-dialog',
9285 6474 modal: true,
9286 6475 autoOpen: false,
9287 6476 closeOnEscape: true,
@@ -9297,19 +6486,11 @@
9297 6486 },
9298 6487 close: function() {
9299 6488 jQuery( '#wpwrap' ).removeClass( 'frm_overlay' );
9300 6489 jQuery( '.spinner' ).css( 'visibility', 'hidden' );
9301 -
9302 - this.removeAttribute( 'data-option-type' );
9303 - const optionType = document.getElementById( 'bulk-option-type' );
9304 - if ( optionType ) {
9305 - optionType.value = '';
9306 - }
9307 6490 }
9308 - };
6491 + });
9309 6492
9310 - $info.dialog( dialogArgs );
9311 -
9312 6493 return $info;
9313 6494 }
9314 6495
9315 6496 function toggle( cname, id ) {
@@ -9337,35 +6518,8 @@
9337 6518 w.off( 'beforeunload.widgets' );
9338 6519 w.off( 'beforeunload.edit-post' );
9339 6520 }
9340 6521
9341 - function addMultiselectLabelListener() {
9342 - const clickListener = ( e ) => {
9343 - if ( 'LABEL' !== e.target.nodeName ) {
9344 - return;
9345 - }
9346 -
9347 - const labelFor = e.target.getAttribute( 'for' );
9348 - if ( ! labelFor ) {
9349 - return;
9350 - }
9351 -
9352 - const input = document.getElementById( labelFor );
9353 - if ( ! input || ! input.nextElementSibling ) {
9354 - return;
9355 - }
9356 -
9357 - const buttonToggle = input.nextElementSibling.querySelector( 'button.dropdown-toggle.multiselect' );
9358 - if ( ! buttonToggle ) {
9359 - return;
9360 - }
9361 -
9362 - const triggerMultiselectClick = () => buttonToggle.click();
9363 - setTimeout( triggerMultiselectClick, 0 );
9364 - };
9365 - document.addEventListener( 'click', clickListener );
9366 - }
9367 -
9368 6522 function maybeChangeEmbedFormMsg() {
9369 6523 var fieldId = jQuery( this ).closest( '.frm-single-settings' ).data( 'fid' );
9370 6524 var fieldItem = document.getElementById( 'frm_field_id_' + fieldId );
9371 6525 if ( null === fieldItem || 'form' !== fieldItem.dataset.type ) {
@@ -9564,90 +6718,16 @@
9564 6718 }, false );
9565 6719 }
9566 6720
9567 6721 function debounce( func, wait = 100 ) {
9568 - return frmDom.util.debounce( func, wait );
9569 - }
9570 -
9571 - function addSaveAndDragIconsToOption( fieldId, liObject ) {
9572 - let li, useTag, useTagHref;
9573 - let hasDragIcon = false;
9574 - let hasSaveIcon = false;
9575 -
9576 - if ( liObject.newOption ) {
9577 - const parser = new DOMParser();
9578 - li = parser.parseFromString( liObject.newOption, 'text/html' ).body.childNodes[0];
9579 - } else {
9580 - li = liObject;
9581 - }
9582 -
9583 - const liIcons = li.querySelectorAll( 'svg' );
9584 -
9585 - liIcons.forEach( ( svg, key ) => {
9586 - useTag = svg.getElementsByTagNameNS( 'http://www.w3.org/2000/svg', 'use' )[0];
9587 - if ( ! useTag ) {
9588 - return;
9589 - }
9590 - useTagHref = useTag.getAttributeNS( 'http://www.w3.org/1999/xlink', 'href' ) || useTag.getAttribute( 'href' );
9591 -
9592 - if ( useTagHref === '#frm_drag_icon' ) {
9593 - hasDragIcon = true;
9594 - }
9595 -
9596 - if ( useTagHref === '#frm_save_icon' ) {
9597 - hasSaveIcon = true;
9598 - }
9599 - });
9600 -
9601 - if ( ! hasDragIcon ) {
9602 - li.prepend( icons.drag.cloneNode( true ) );
9603 - }
9604 -
9605 - if ( li.querySelector( `[id^=field_key_${fieldId}-]` ) && ! hasSaveIcon ) {
9606 - li.querySelector( `[id^=field_key_${fieldId}-]` ).after( icons.save.cloneNode( true ) );
9607 - }
9608 -
9609 - if ( liObject.newOption ) {
9610 - liObject.newOption = li;
9611 - }
9612 - }
9613 -
9614 - function maybeAddSaveAndDragIcons( fieldId ) {
9615 - fieldOptions = document.querySelectorAll( `[id^=frm_delete_field_${fieldId}-]` );
9616 - // return if there are no options.
9617 - if ( fieldOptions.length < 2 ) {
9618 - return;
9619 - }
9620 -
9621 - let options = [ ...fieldOptions ].slice( 1 );
9622 - options.forEach( ( li, _key ) => {
9623 - if ( li.classList.contains( 'frm_other_option' ) ) {
9624 - return;
9625 - }
9626 - addSaveAndDragIconsToOption( fieldId, li );
9627 - });
9628 - }
9629 -
9630 - function initOnSubmitAction() {
9631 - const onChangeType = event => {
9632 - if ( ! event.target.checked ) {
9633 - return;
9634 - }
9635 -
9636 - const actionEl = event.target.closest( '.frm_form_action_settings' );
9637 - actionEl.querySelectorAll( '.frm_on_submit_dependent_setting:not(.frm_hidden)' ).forEach( el => {
9638 - el.classList.add( 'frm_hidden' );
9639 - });
9640 -
9641 - const activeEls = actionEl.querySelectorAll( '.frm_on_submit_dependent_setting[data-show-if-' + event.target.value + ']' );
9642 - activeEls.forEach( activeEl => {
9643 - activeEl.classList.remove( 'frm_hidden' );
9644 - });
9645 -
9646 - actionEl.setAttribute( 'data-on-submit-type', event.target.value );
6722 + let timeout;
6723 + return function( ...args ) {
6724 + clearTimeout( timeout );
6725 + timeout = setTimeout(
6726 + () => func.apply( this, args ),
6727 + wait
6728 + );
9647 6729 };
9648 -
9649 - frmDom.util.documentOn( 'change', '.frm_on_submit_type input[type="radio"]', onChangeType );
9650 6730 }
9651 6731
9652 6732 return {
9653 6733 init: function() {
@@ -9666,15 +6746,8 @@
9666 6746 if ( typeof thisFormId === 'undefined' ) {
9667 6747 thisFormId = jQuery( document.getElementById( 'form_id' ) ).val();
9668 6748 }
9669 6749
9670 - // Add event listener for dismissible warning messages.
9671 - document.querySelectorAll( '.frm-warning-dismiss' ).forEach( ( dismissIcon ) => {
9672 - onClickPreventDefault( dismissIcon, dismissWarningMessage );
9673 - });
9674 -
9675 - frmAdminBuild.inboxBannerInit();
9676 -
9677 6750 if ( $newFields.length > 0 ) {
9678 6751 // only load this on the form builder page
9679 6752 frmAdminBuild.buildInit();
9680 6753 } else if ( document.getElementById( 'frm_notification_settings' ) !== null ) {
@@ -9682,8 +6755,11 @@
9682 6755 frmAdminBuild.settingsInit();
9683 6756 } else if ( document.getElementById( 'frm_styling_form' ) !== null ) {
9684 6757 // load styling settings js
9685 6758 frmAdminBuild.styleInit();
6759 + } else if ( document.getElementById( 'frm_custom_css_box' ) !== null ) {
6760 + // load styling settings js
6761 + frmAdminBuild.customCSSInit();
9686 6762 } else if ( document.getElementById( 'form_global_settings' ) !== null ) {
9687 6763 // global settings page
9688 6764 frmAdminBuild.globalSettingsInit();
9689 6765 } else if ( document.getElementById( 'frm_export_xml' ) !== null ) {
@@ -9738,24 +6814,17 @@
9738 6814
9739 6815 // tabs
9740 6816 jQuery( document ).on( 'click', '#frm-nav-tabs a', clickNewTab );
9741 6817 jQuery( '.post-type-frm_display .frm-nav-tabs a, .frm-category-tabs a' ).on( 'click', function() {
9742 - const showUpgradeTab = this.classList.contains( 'frm_show_upgrade_tab' );
9743 - if ( this.classList.contains( 'frm_noallow' ) && ! showUpgradeTab ) {
9744 - return;
6818 + if ( ! this.classList.contains( 'frm_noallow' ) ) {
6819 + clickTab( this );
6820 + return false;
9745 6821 }
9746 -
9747 - if ( showUpgradeTab ) {
9748 - populateUpgradeTab( this );
9749 - }
9750 -
9751 - clickTab( this );
9752 - return false;
9753 6822 });
9754 6823 clickTab( jQuery( '.starttab a' ), 'auto' );
9755 6824
9756 6825 // submit the search form with dropdown
9757 - jQuery( document ).on( 'click', '#frm-fid-search-menu a', function() {
6826 + jQuery( '#frm-fid-search-menu a' ).on( 'click', function() {
9758 6827 var val = this.id.replace( 'fid-', '' );
9759 6828 jQuery( 'select[name="fid"]' ).val( val );
9760 6829 triggerSubmit( document.getElementById( 'posts-filter' ) );
9761 6830 return false;
@@ -9764,9 +6833,9 @@
9764 6833 jQuery( '.frm_select_box' ).on( 'click focus', function() {
9765 6834 this.select();
9766 6835 });
9767 6836
9768 - jQuery( document ).on( 'input search change', '.frm-auto-search:not(#frm_new_form_modal #template-search-input)', searchContent );
6837 + jQuery( document ).on( 'input search change', '.frm-auto-search', searchContent );
9769 6838 jQuery( document ).on( 'focusin click', '.frm-auto-search', stopPropagation );
9770 6839 var autoSearch = jQuery( '.frm-auto-search' );
9771 6840 if ( autoSearch.val() !== '' ) {
9772 6841 autoSearch.trigger( 'keyup' );
@@ -9780,68 +6849,33 @@
9780 6849 jQuery( document ).on( 'click', '.frm-solution-multiple', installMultipleAddons );
9781 6850
9782 6851 // prevent annoying confirmation message from WordPress
9783 6852 jQuery( 'button, input[type=submit]' ).on( 'click', removeWPUnload );
9784 -
9785 - addMultiselectLabelListener();
9786 -
9787 - frmAdminBuild.hooks.addFilter(
9788 - 'frm_before_embed_modal',
9789 - ( ids, { element, type }) => {
9790 - if ( 'form' !== type ) {
9791 - return ids;
9792 - }
9793 -
9794 - let formId, formKey;
9795 - const row = element.closest( 'tr' );
9796 -
9797 - if ( row ) {
9798 - // Embed icon on form index.
9799 - formId = parseInt( row.querySelector( '.column-id' ).textContent );
9800 - formKey = row.querySelector( '.column-form_key' ).textContent;
9801 - } else {
9802 - // Embed button in form builder / form settings.
9803 - formId = document.getElementById( 'form_id' ).value;
9804 -
9805 - const formKeyInput = document.getElementById( 'frm_form_key' );
9806 - if ( formKeyInput ) {
9807 - formKey = formKeyInput.value;
9808 - } else {
9809 - const previewDrop = document.getElementById( 'frm-previewDrop' );
9810 - if ( previewDrop ) {
9811 - formKey = previewDrop.nextElementSibling.querySelector( '.dropdown-item a' ).getAttribute( 'href' ).split( 'form=' )[1];
9812 - }
9813 - }
9814 - }
9815 -
9816 - return [ formId, formKey ];
9817 - }
9818 - );
9819 -
9820 - document.querySelectorAll( '#frm-show-fields > li, .frm_grid_container li' ).forEach( ( el, _key ) => {
9821 - el.addEventListener( 'click', function() {
9822 - let fieldId = this.querySelector( 'li' )?.dataset.fid || this.dataset.fid;
9823 - maybeAddSaveAndDragIcons( fieldId );
9824 - });
9825 - });
9826 6853 },
9827 6854
9828 6855 buildInit: function() {
9829 - let loadFieldId, $builderForm, builderArea;
9830 -
9831 - debouncedSyncAfterDragAndDrop = debounce( syncAfterDragAndDrop, 10 );
9832 - postBodyContent = document.getElementById( 'post-body-content' );
9833 - $postBodyContent = jQuery( postBodyContent );
9834 -
9835 6856 if ( jQuery( '.frm_field_loading' ).length ) {
9836 - loadFieldId = jQuery( '.frm_field_loading' ).first().attr( 'id' );
6857 + var loadFieldId = jQuery( '.frm_field_loading' ).first().attr( 'id' );
9837 6858 loadFields( loadFieldId );
9838 6859 }
9839 6860
9840 6861 setupSortable( 'ul.frm_sorting' );
9841 6862
9842 - document.querySelectorAll( '.field_type_list > li:not(.frm_show_upgrade)' ).forEach( makeDraggable );
6863 + // Show message if section has no fields inside
6864 + var frmSorting = jQuery( '.start_divider.frm_sorting' );
6865 + for ( i = 0; i < frmSorting.length; i++ ) {
6866 + if ( frmSorting[i].children.length < 2 ) {
6867 + jQuery( frmSorting[i]).parent().children( '.frm_no_section_fields' ).addClass( 'frm_block' );
6868 + }
6869 + }
9843 6870
6871 + jQuery( '.field_type_list > li:not(.frm_noallow)' ).draggable({
6872 + connectToSortable: '#frm-show-fields',
6873 + helper: 'clone',
6874 + revert: 'invalid',
6875 + delay: 10,
6876 + cancel: '.frm-dropdown-menu'
6877 + });
9844 6878 jQuery( 'ul.field_type_list, .field_type_list li, ul.frm_code_list, .frm_code_list li, .frm_code_list li a, #frm_adv_info #category-tabs li, #frm_adv_info #category-tabs li a' ).disableSelection();
9845 6879
9846 6880 jQuery( '.frm_submit_ajax' ).on( 'click', submitBuild );
9847 6881 jQuery( '.frm_submit_no_ajax' ).on( 'click', submitNoAjax );
@@ -9848,9 +6882,9 @@
9848 6882
9849 6883 jQuery( 'a.edit-form-status' ).on( 'click', slideDown );
9850 6884 jQuery( '.cancel-form-status' ).on( 'click', slideUp );
9851 6885 jQuery( '.save-form-status' ).on( 'click', function() {
9852 - const newStatus = jQuery( document.getElementById( 'form_change_status' ) ).val();
6886 + var newStatus = jQuery( document.getElementById( 'form_change_status' ) ).val();
9853 6887 jQuery( 'input[name="new_status"]' ).val( newStatus );
9854 6888 jQuery( document.getElementById( 'form-status-display' ) ).html( newStatus );
9855 6889 jQuery( '.cancel-form-status' ).trigger( 'click' );
9856 6890 return false;
@@ -9862,14 +6896,15 @@
9862 6896
9863 6897 initiateMultiselect();
9864 6898 renumberPageBreaks();
9865 6899
9866 - $builderForm = jQuery( builderForm );
9867 - builderArea = document.getElementById( 'frm_form_editor_container' );
6900 + var $builderForm = jQuery( builderForm );
6901 + var builderArea = document.getElementById( 'frm_form_editor_container' );
9868 6902 $builderForm.on( 'click', '.frm_add_logic_row', addFieldLogicRow );
9869 6903 $builderForm.on( 'click', '.frm_add_watch_lookup_row', addWatchLookupRow );
9870 6904 $builderForm.on( 'change', '.frm_get_values_form', updateGetValueFieldSelection );
9871 6905 $builderForm.on( 'change', '.frm_logic_field_opts', getFieldValues );
6906 + $builderForm.on( 'change', '.scale_maxnum, .scale_minnum', setScaleValues );
9872 6907 $builderForm.on( 'change', '.radio_maxnum', setStarValues );
9873 6908 $builderForm.on( 'frm-multiselect-changed', 'select[name^="field_options[admin_only_"]', adjustVisibilityValuesForEveryoneValues );
9874 6909
9875 6910 jQuery( document.getElementById( 'frm-insert-fields' ) ).on( 'click', '.frm_add_field', addFieldClick );
@@ -9874,9 +6909,9 @@
9874 6909
9875 6910 jQuery( document.getElementById( 'frm-insert-fields' ) ).on( 'click', '.frm_add_field', addFieldClick );
9876 6911 $newFields.on( 'click', '.frm_clone_field', duplicateField );
9877 6912 $builderForm.on( 'blur', 'input[id^="frm_calc"]', checkCalculationCreatedByUser );
9878 - $builderForm.on( 'change', 'input.frm_format_opt, input.frm_max_length_opt', toggleInvalidMsg );
6913 + $builderForm.on( 'change', 'input.frm_format_opt', toggleInvalidMsg );
9879 6914 $builderForm.on( 'change click', '[data-changeme]', liveChanges );
9880 6915 $builderForm.on( 'click', 'input.frm_req_field', markRequired );
9881 6916 $builderForm.on( 'click', '.frm_mark_unique', markUnique );
9882 6917
@@ -9893,10 +6928,8 @@
9893 6928 jQuery( builderArea ).on( 'click', '.frm-collapse-page', maybeCollapsePage );
9894 6929 jQuery( builderArea ).on( 'click', '.frm-collapse-section', maybeCollapseSection );
9895 6930 $builderForm.on( 'click', '.frm-single-settings h3', maybeCollapseSettings );
9896 6931
9897 - jQuery( builderArea ).on( 'show.bs.dropdown hide.bs.dropdown', changeSectionStyle );
9898 -
9899 6932 $builderForm.on( 'click', '.frm_toggle_sep_values', toggleSepValues );
9900 6933 $builderForm.on( 'click', '.frm_toggle_image_options', toggleImageOptions );
9901 6934 $builderForm.on( 'click', '.frm_remove_image_option', removeImageFromOption );
9902 6935 $builderForm.on( 'click', '.frm_choose_image_box', addImageToOption );
@@ -9905,30 +6938,8 @@
9905 6938 $builderForm.on( 'click', '.frm_multiselect_opt', toggleMultiselect );
9906 6939 $newFields.on( 'mousedown', 'input, textarea, select', stopFieldFocus );
9907 6940 $newFields.on( 'click', 'input[type=radio], input[type=checkbox]', stopFieldFocus );
9908 6941 $newFields.on( 'click', '.frm_delete_field', clickDeleteField );
9909 - $newFields.on( 'click', '.frm_select_field', clickSelectField );
9910 - jQuery( document ).on( 'click', '.frm_delete_field_group', clickDeleteFieldGroup );
9911 - jQuery( document ).on( 'click', '.frm_clone_field_group', duplicateFieldGroup );
9912 - jQuery( document ).on( 'click', '#frm_field_group_controls > span:first-child', clickFieldGroupLayout );
9913 - jQuery( document ).on( 'click', '.frm-row-layout-option', handleFieldGroupLayoutOptionClick );
9914 - jQuery( document ).on( 'click', '.frm-merge-fields-into-row .frm-row-layout-option', handleFieldGroupLayoutOptionInsideMergeClick );
9915 - jQuery( document ).on( 'click', '.frm-custom-field-group-layout', customFieldGroupLayoutClick );
9916 - jQuery( document ).on( 'click', '.frm-merge-fields-into-row .frm-custom-field-group-layout', customFieldGroupLayoutInsideMergeClick );
9917 - jQuery( document ).on( 'click', '.frm-break-field-group', breakFieldGroupClick );
9918 - $newFields.on( 'click', '#frm_field_group_popup .frm_grid_container input', focusFieldGroupInputOnClick );
9919 - jQuery( document ).on( 'click', '.frm-cancel-custom-field-group-layout', cancelCustomFieldGroupClick );
9920 - jQuery( document ).on( 'click', '.frm-save-custom-field-group-layout', saveCustomFieldGroupClick );
9921 - $newFields.on( 'click', 'ul.frm_sorting', fieldGroupClick );
9922 - jQuery( document ).on( 'click', '.frm-merge-fields-into-row', mergeFieldsIntoRowClick );
9923 - jQuery( document ).on( 'click', '.frm-delete-field-groups', deleteFieldGroupsClick );
9924 - $newFields.on( 'click', '.frm-field-action-icons [data-toggle="dropdown"]', function() {
9925 - this.closest( 'li.form-field' ).classList.add( 'frm-field-settings-open' );
9926 - jQuery( document ).on( 'click', '#frm_builder_page', handleClickOutsideOfFieldSettings );
9927 - });
9928 - $newFields.on( 'mousemove', 'ul.frm_sorting', checkForMultiselectKeysOnMouseMove );
9929 - $newFields.on( 'show.bs.dropdown', '.frm-field-action-icons', onFieldActionDropdownShow );
9930 - jQuery( document ).on( 'show.bs.dropdown', '#frm_field_group_controls', onFieldGroupActionDropdownShow );
9931 6942 $builderForm.on( 'click', '.frm_single_option a[data-removeid]', deleteFieldOption );
9932 6943 $builderForm.on( 'mousedown', '.frm_single_option input[type=radio]', maybeUncheckRadio );
9933 6944 $builderForm.on( 'focusin', '.frm_single_option input[type=text]', maybeClearOptText );
9934 6945 $builderForm.on( 'click', '.frm_add_opt', addFieldOption );
@@ -9954,9 +6965,9 @@
9954 6965 $builderForm.on( 'change', '.frm_include_extras_field', rePopCalcFieldsForSummary );
9955 6966 $builderForm.on( 'change', 'select[name^="field_options[form_select_"]', maybeChangeEmbedFormMsg );
9956 6967
9957 6968 jQuery( document ).on( 'submit', '#frm_js_build_form', buildSubmittedNoAjax );
9958 - jQuery( document ).on( 'change', '#frm_builder_page input:not(.frm-search-input):not(.frm-custom-grid-size-input), #frm_builder_page select, #frm_builder_page textarea', fieldUpdated );
6969 + jQuery( document ).on( 'change', '#frm_builder_page input:not(.frm-search-input), #frm_builder_page select, #frm_builder_page textarea', fieldUpdated );
9959 6970
9960 6971 popAllProductFields();
9961 6972
9962 6973 jQuery( document ).on( 'change', '.frmjs_prod_data_type_opt', toggleProductType );
@@ -9965,20 +6976,17 @@
9965 6976 jQuery( document ).on( 'blur', '.frm-single-settings ul input[type="text"][name^="field_options[options_"]', onOptionTextBlur );
9966 6977
9967 6978 initBulkOptionsOverlay();
9968 6979 hideEmptyEle();
6980 + maybeDisableAddSummaryBtn();
9969 6981 maybeHideQuantityProductFieldOption();
9970 6982 handleNameFieldOnFormBuilder();
9971 - toggleSectionHolder();
9972 - handleShowPasswordLiveUpdate();
9973 6983 },
9974 6984
9975 6985 settingsInit: function() {
9976 - const $formActions = jQuery( document.getElementById( 'frm_notification_settings' ) );
9977 -
9978 - let formSettings, $loggedIn, $cookieExp, $editable;
9979 -
9980 - // BCC, CC, and Reply To button functionality
6986 + var formSettings, $loggedIn, $cookieExp, $editable,
6987 + $formActions = jQuery( document.getElementById( 'frm_notification_settings' ) );
6988 + //BCC, CC, and Reply To button functionality
9981 6989 $formActions.on( 'click', '.frm_email_buttons', showEmailRow );
9982 6990 $formActions.on( 'click', '.frm_remove_field', hideEmailRow );
9983 6991 $formActions.on( 'change', '.frm_to_row, .frm_from_row', showEmailWarning );
9984 6992 $formActions.on( 'change', '.frm_tax_selector', changePosttaxRow );
@@ -9989,9 +6997,9 @@
9989 6997 $formActions.on( 'click', '.frm_add_postmeta_row', addPostmetaRow );
9990 6998 $formActions.on( 'click', '.frm_add_posttax_row', addPosttaxRow );
9991 6999 $formActions.on( 'click', '.frm_toggle_cf_opts', toggleCfOpts );
9992 7000 $formActions.on( 'click', '.frm_duplicate_form_action', copyFormAction );
9993 - jQuery( document ).on( 'change', 'select[data-toggleclass], input[data-toggleclass]', toggleFormOpts );
7001 + jQuery( 'select[data-toggleclass], input[data-toggleclass]' ).on( 'change', toggleFormOpts );
9994 7002 jQuery( '.frm_actions_list' ).on( 'click', '.frm_active_action', addFormAction );
9995 7003 jQuery( '#frm-show-groups, #frm-hide-groups' ).on( 'click', toggleActionGroups );
9996 7004 initiateMultiselect();
9997 7005
@@ -9999,9 +7007,9 @@
9999 7007 jQuery( 'ul.frm_actions_list li' ).each( function() {
10000 7008 checkActiveAction( jQuery( this ).children( 'a' ).data( 'actiontype' ) );
10001 7009
10002 7010 // If the icon is a background image, don't add BG color.
10003 - const icon = jQuery( this ).find( 'i' );
7011 + var icon = jQuery( this ).find( 'i' );
10004 7012 if ( icon.css( 'background-image' ) !== 'none' ) {
10005 7013 icon.addClass( 'frm-inverse' );
10006 7014 }
10007 7015 });
@@ -10016,48 +7024,22 @@
10016 7024 formSettings.on( 'change', '#logic_link_submit', toggleSubmitLogic );
10017 7025 formSettings.on( 'click', '.frm_add_submit_logic', addSubmitLogic );
10018 7026 formSettings.on( 'change', '.frm_submit_logic_field_opts', addSubmitLogicOpts );
10019 7027
10020 - document.addEventListener(
10021 - 'click',
10022 - function handleImageUploadClickEvents( event ) {
10023 - const { target } = event;
10024 -
10025 - if ( ! target.closest( '.frm_image_preview_wrapper' ) ) {
10026 - return;
10027 - }
10028 -
10029 - if ( target.closest( '.frm_choose_image_box' ) ) {
10030 - addImageToOption.bind( target )( event );
10031 - return;
10032 - }
10033 -
10034 - if ( target.closest( '.frm_remove_image_option' ) ) {
10035 - removeImageFromOption.bind( target )( event );
10036 - }
10037 - }
10038 - );
10039 -
10040 7028 // Close shortcode modal on click.
10041 7029 formSettings.on( 'mouseup', '*:not(.frm-show-box)', function( e ) {
10042 7030 e.stopPropagation();
10043 -
10044 - if ( e.target.classList.contains( 'frm-show-box' ) || e.target.parentElement.classList.contains( 'frm-show-box' ) ) {
7031 + if ( e.target.classList.contains( 'frm-show-box' ) ) {
10045 7032 return;
10046 7033 }
7034 + var sidebar = document.getElementById( 'frm_adv_info' ),
7035 + isChild = jQuery( e.target ).closest( '#frm_adv_info' ).length > 0;
10047 7036
10048 - const sidebar = document.getElementById( 'frm_adv_info' );
10049 - if ( ! sidebar ) {
10050 - return;
10051 - }
10052 -
10053 7037 if ( sidebar.getAttribute( 'data-fills' ) === e.target.id && typeof e.target.id !== 'undefined' ) {
10054 7038 return;
10055 7039 }
10056 7040
10057 - const isChild = jQuery( e.target ).closest( '#frm_adv_info' ).length > 0;
10058 -
10059 - if ( ! isChild && sidebar.display !== 'none' ) {
7041 + if ( sidebar !== null && ! isChild && sidebar.display !== 'none' ) {
10060 7042 hideShortcodes( sidebar );
10061 7043 }
10062 7044 });
10063 7045
@@ -10063,9 +7045,9 @@
10063 7045
10064 7046 //Warning when user selects "Do not store entries ..."
10065 7047 jQuery( document.getElementById( 'no_save' ) ).on( 'change', function() {
10066 7048 if ( this.checked ) {
10067 - if ( confirm( frm_admin_js.no_save_warning ) !== true ) { // eslint-disable-line camelcase
7049 + if ( confirm( frm_admin_js.no_save_warning ) !== true ) {
10068 7050 // Uncheck box if user hits "Cancel"
10069 7051 jQuery( this ).attr( 'checked', false );
10070 7052 }
10071 7053 }
@@ -10070,9 +7052,13 @@
10070 7052 }
10071 7053 }
10072 7054 });
10073 7055
10074 - jQuery( 'select[name="options[edit_action]"]' ).on( 'change', showSuccessOpt );
7056 + //Show/hide Messages header
7057 + jQuery( '#editable, #edit_action, #save_draft, #success_action' ).on( 'change', function() {
7058 + maybeShowFormMessages();
7059 + });
7060 + jQuery( 'select[name="options[success_action]"], select[name="options[edit_action]"]' ).on( 'change', showSuccessOpt );
10075 7061
10076 7062 $loggedIn = document.getElementById( 'logged_in' );
10077 7063 jQuery( $loggedIn ).on( 'change', function() {
10078 7064 if ( this.checked ) {
@@ -10145,12 +7131,8 @@
10145 7131 jQuery( document ).on( 'change', '#form_settings_page input:not(.frm-search-input), #form_settings_page select, #form_settings_page textarea', fieldUpdated );
10146 7132
10147 7133 // Page Selection Autocomplete
10148 7134 initSelectionAutocomplete();
10149 -
10150 - jQuery( document ).on( 'frm-action-loaded', onActionLoaded );
10151 -
10152 - initOnSubmitAction();
10153 7135 },
10154 7136
10155 7137 panelInit: function() {
10156 7138 var customPanel, settingsPage, viewPage, insertFieldsTab;
@@ -10307,17 +7289,136 @@
10307 7289 jQuery( document ).on( 'submit', '#frm-new-template', installTemplate );
10308 7290 },
10309 7291
10310 7292 styleInit: function() {
10311 - const $previewWrapper = jQuery( '.frm_image_preview_wrapper' );
10312 - $previewWrapper.on( 'click', '.frm_choose_image_box', addImageToOption );
10313 - $previewWrapper.on( 'click', '.frm_remove_image_option', removeImageFromOption );
7293 + collapseAllSections();
10314 7294
10315 - wp.hooks.doAction( 'frm_style_editor_init' );
7295 + document.getElementById( 'frm_field_height' ).addEventListener( 'change', textSquishCheck );
7296 + document.getElementById( 'frm_field_font_size' ).addEventListener( 'change', textSquishCheck );
7297 + document.getElementById( 'frm_field_pad' ).addEventListener( 'change', textSquishCheck );
7298 +
7299 + jQuery( 'input.hex' ).wpColorPicker({
7300 + change: function( event ) {
7301 + var hexcolor = jQuery( this ).wpColorPicker( 'color' );
7302 + jQuery( event.target ).val( hexcolor ).trigger( 'change' );
7303 + }
7304 + });
7305 + jQuery( '.wp-color-result-text' ).text( function( i, oldText ) {
7306 + return oldText === 'Select Color' ? 'Select' : oldText;
7307 + });
7308 +
7309 + function changeStyling() {
7310 + var locStr = jQuery( 'input[name^="frm_style_setting[post_content]"], select[name^="frm_style_setting[post_content]"], textarea[name^="frm_style_setting[post_content]"], input[name="style_name"]' ).serializeArray();
7311 + locStr = JSON.stringify( locStr );
7312 + jQuery.ajax({
7313 + type: 'POST', url: ajaxurl,
7314 + data: {
7315 + action: 'frm_change_styling',
7316 + nonce: frmGlobal.nonce,
7317 + frm_style_setting: locStr
7318 + },
7319 + success: function( css ) {
7320 + document.getElementById( 'this_css' ).innerHTML = css;
7321 + }
7322 + });
7323 + }
7324 +
7325 + // update styling on change
7326 + jQuery( '#frm_styling_form .styling_settings' ).on( 'change', debounce( changeStyling, 100 ) );
7327 +
7328 + // menu tabs
7329 + jQuery( '#menu-settings-column' ).on( 'click', function( e ) {
7330 + var panelId, wrapper,
7331 + target = jQuery( e.target );
7332 +
7333 + if ( e.target.className.indexOf( 'nav-tab-link' ) !== -1 ) {
7334 +
7335 + panelId = target.data( 'type' );
7336 +
7337 + wrapper = target.parents( '.accordion-section-content' ).first();
7338 +
7339 +
7340 + jQuery( '.tabs-panel-active', wrapper ).removeClass( 'tabs-panel-active' ).addClass( 'tabs-panel-inactive' );
7341 + jQuery( '#' + panelId, wrapper ).removeClass( 'tabs-panel-inactive' ).addClass( 'tabs-panel-active' );
7342 +
7343 + jQuery( '.tabs', wrapper ).removeClass( 'tabs' );
7344 + target.parent().addClass( 'tabs' );
7345 +
7346 + // select the search bar
7347 + jQuery( '.quick-search', wrapper ).trigger( 'focus' );
7348 +
7349 + e.preventDefault();
7350 + }
7351 + });
7352 +
7353 + jQuery( '.multiselect-container.frm-dropdown-menu li a' ).on( 'click', function() {
7354 + var radio = this.children[0].children[0];
7355 + var btnGrp = jQuery( this ).closest( '.btn-group' );
7356 + var btnId = btnGrp.attr( 'id' );
7357 + document.getElementById( btnId.replace( '_select', '' ) ).value = radio.value;
7358 + btnGrp.children( 'button' ).html( radio.nextElementSibling.innerHTML + ' <b class="caret"></b>' );
7359 +
7360 + // set active class
7361 + btnGrp.find( 'li.active' ).removeClass( 'active' );
7362 + jQuery( this ).closest( 'li' ).addClass( 'active' );
7363 + });
7364 +
7365 + jQuery( '#frm_confirm_modal' ).on( 'click', '[data-resetstyle]', function( e ) {
7366 + var button = document.getElementById( 'frm_reset_style' );
7367 +
7368 + button.classList.add( 'frm_loading_button' );
7369 + e.stopPropagation();
7370 +
7371 + jQuery.ajax({
7372 + type: 'POST', url: ajaxurl,
7373 + data: {action: 'frm_settings_reset', nonce: frmGlobal.nonce},
7374 + success: function( errObj ) {
7375 + var key;
7376 + errObj = errObj.replace( /^\s+|\s+$/g, '' );
7377 + if ( errObj.indexOf( '{' ) === 0 ) {
7378 + errObj = JSON.parse( errObj );
7379 + }
7380 + for ( key in errObj ) {
7381 + jQuery( 'input[name$="[' + key + ']"], select[name$="[' + key + ']"]' ).val( errObj[key]);
7382 + }
7383 + jQuery( '#frm_submit_style, #frm_auto_width' ).prop( 'checked', false );
7384 + triggerChange( document.getElementById( 'frm_fieldset' ) );
7385 + button.classList.remove( 'frm_loading_button' );
7386 + }
7387 + });
7388 + });
7389 +
7390 + jQuery( '.frm_pro_form #datepicker_sample' ).datepicker({ changeMonth: true, changeYear: true });
7391 +
7392 + jQuery( document.getElementById( 'frm_position' ) ).on( 'change', setPosClass );
7393 +
7394 + jQuery( 'select[name$="[theme_selector]"]' ).on( 'change', function() {
7395 + var themeVal = jQuery( this ).val();
7396 + var css = themeVal;
7397 + if ( themeVal !== -1 ) {
7398 + if ( themeVal === 'ui-lightness' && frm_admin_js.pro_url !== '' ) {
7399 + css = frm_admin_js.pro_url + '/css/ui-lightness/jquery-ui.css';
7400 + jQuery( '.frm_date_color' ).show();
7401 + } else {
7402 + css = frm_admin_js.jquery_ui_url + '/themes/' + themeVal + '/jquery-ui.css';
7403 + jQuery( '.frm_date_color' ).hide();
7404 + }
7405 + }
7406 +
7407 + updateUICSS( css );
7408 + document.getElementById( 'frm_theme_css' ).value = themeVal;
7409 + return false;
7410 + }).trigger( 'change' );
10316 7411 },
10317 7412
10318 7413 customCSSInit: function() {
10319 - console.warn( 'Calling frmAdminBuild.customCSSInit is deprecated.' );
7414 + /* deprecated since WP 4.9 */
7415 + var customCSS = document.getElementById( 'frm_custom_css_box' );
7416 + if ( customCSS !== null ) {
7417 + CodeMirror.fromTextArea( customCSS, {
7418 + lineNumbers: true
7419 + });
7420 + }
10320 7421 },
10321 7422
10322 7423 globalSettingsInit: function() {
10323 7424 var licenseTab;
@@ -10341,17 +7442,8 @@
10341 7442 action: 'frm_lite_settings_upgrade'
10342 7443 });
10343 7444 jQuery( '.settings-lite-cta' ).remove();
10344 7445 });
10345 -
10346 - const captchaType = document.getElementById( 'frm_re_type' );
10347 - if ( captchaType ) {
10348 - captchaType.addEventListener( 'change', handleCaptchaTypeChange );
10349 - }
10350 -
10351 - document.querySelector( '.frm_captchas' ).addEventListener( 'change', function() {
10352 - document.querySelector( '.captcha_settings .frm_note_style' ).classList.toggle( 'frm_hidden' );
10353 - });
10354 7446 },
10355 7447
10356 7448 exportInit: function() {
10357 7449 jQuery( '.frm_form_importer' ).on( 'submit', startFormMigration );
@@ -10357,10 +7449,9 @@
10357 7449 jQuery( '.frm_form_importer' ).on( 'submit', startFormMigration );
10358 7450 jQuery( document.getElementById( 'frm_export_xml' ) ).on( 'submit', validateExport );
10359 7451 jQuery( '#frm_export_xml input, #frm_export_xml select' ).on( 'change', removeExportError );
10360 7452 jQuery( 'input[name="frm_import_file"]' ).on( 'change', checkCSVExtension );
10361 - document.querySelector( 'select[name="format"]' ).addEventListener( 'change', exportTypeChanged );
10362 -
7453 + jQuery( 'select[name="format"]' ).on( 'change', checkExportTypes ).trigger( 'change' );
10363 7454 jQuery( 'input[name="frm_export_forms[]"]' ).on( 'click', preventMultipleExport );
10364 7455 initiateMultiselect();
10365 7456
10366 7457 jQuery( '.frm-feature-banner .dismiss' ).on( 'click', function( event ) {
@@ -10371,50 +7462,10 @@
10371 7462 nonce: frmGlobal.nonce
10372 7463 });
10373 7464 this.parentElement.remove();
10374 7465 });
10375 -
10376 - showOrHideRepeaters( getExportOption() );
10377 -
10378 - document.querySelector( '#frm-export-select-all' ).addEventListener( 'change', event => {
10379 - document.querySelectorAll( '[name="frm_export_forms[]"]' ).forEach( cb => cb.checked = event.target.checked );
10380 - });
10381 7466 },
10382 7467
10383 - inboxBannerInit: function() {
10384 - const banner = document.getElementById( 'frm_banner' );
10385 - if ( ! banner ) {
10386 - return;
10387 - }
10388 -
10389 - const dismissButton = banner.querySelector( '.frm-banner-dismiss' );
10390 - document.addEventListener(
10391 - 'click',
10392 - function( event ) {
10393 - if ( event.target !== dismissButton ) {
10394 - return;
10395 - }
10396 -
10397 - const data = {
10398 - action: 'frm_inbox_dismiss',
10399 - key: banner.dataset.key,
10400 - nonce: frmGlobal.nonce
10401 - };
10402 - postAjax(
10403 - data,
10404 - function() {
10405 - jQuery( banner ).fadeOut(
10406 - 400,
10407 - function() {
10408 - banner.remove();
10409 - }
10410 - );
10411 - }
10412 - );
10413 - }
10414 - );
10415 - },
10416 -
10417 7468 updateOpts: function( fieldId, opts, modal ) {
10418 7469 var separate = usingSeparateValues( fieldId ),
10419 7470 action = isProductField( fieldId ) ? 'frm_bulk_products' : 'frm_import_options';
10420 7471 jQuery.ajax({
@@ -10449,69 +7500,18 @@
10449 7500 if ( isTemplate !== null ) {
10450 7501 url = url + '&is_template=' + isTemplate;
10451 7502 }
10452 7503 location.href = url;
10453 - },
10454 -
10455 - /**
10456 - * @since 5.0.04
10457 - */
10458 - hooks: {
10459 - applyFilters: function( hookName, ...args ) {
10460 - return wp.hooks.applyFilters( hookName, ...args );
10461 - },
10462 - addFilter: function( hookName, callback, priority ) {
10463 - return wp.hooks.addFilter( hookName, 'formidable', callback, priority );
10464 - },
10465 - doAction: function( hookName, ...args ) {
10466 - return wp.hooks.doAction( hookName, ...args );
10467 - },
10468 - addAction: function( hookName, callback, priority ) {
10469 - return wp.hooks.addAction( hookName, 'formidable', callback, priority );
10470 - }
10471 - },
10472 -
10473 - infoModal: infoModal,
10474 - addRadioCheckboxOpt: addRadioCheckboxOpt
7504 + }
10475 7505 };
10476 7506 }
10477 7507
10478 7508 frmAdminBuild = frmAdminBuildJS();
10479 7509
10480 -jQuery( document ).ready(
10481 - () => {
10482 - frmAdminBuild.init();
7510 +jQuery( document ).ready( function( $ ) {
7511 + frmAdminBuild.init();
7512 +});
10483 7513
10484 - frmDom.bootstrap.setupBootstrapDropdowns( convertOldBootstrapDropdownsToBootstrap4 );
10485 - function convertOldBootstrapDropdownsToBootstrap4( frmDropdownMenu ) {
10486 - const toggle = frmDropdownMenu.querySelector( '.frm-dropdown-toggle' );
10487 - if ( toggle ) {
10488 - if ( ! toggle.hasAttribute( 'role' ) ) {
10489 - toggle.setAttribute( 'role', 'button' );
10490 - }
10491 - if ( ! toggle.hasAttribute( 'tabindex' ) ) {
10492 - toggle.setAttribute( 'tabindex', 0 );
10493 - }
10494 - }
10495 -
10496 - // Convert <li> and <ul> tags.
10497 - if ( 'UL' === frmDropdownMenu.tagName ) {
10498 - convertBootstrapUl( frmDropdownMenu );
10499 - }
10500 - }
10501 -
10502 - function convertBootstrapUl( ul ) {
10503 - let html = ul.outerHTML;
10504 - html = html.replace( '<ul ', '<div ' );
10505 - html = html.replace( '</ul>', '</div>' );
10506 - html = html.replaceAll( '<li>', '<div class="dropdown-item">' );
10507 - html = html.replaceAll( '<li class="', '<div class="dropdown-item ' );
10508 - html = html.replaceAll( '</li>', '</div>' );
10509 - ul.outerHTML = html;
10510 - }
10511 - }
10512 -);
10513 -
10514 7514 function frm_remove_tag( htmlTag ) { // eslint-disable-line camelcase
10515 7515 console.warn( 'DEPRECATED: function frm_remove_tag in v2.0' );
10516 7516 jQuery( htmlTag ).remove();
10517 7517 }
@@ -10583,9 +7583,9 @@
10583 7583 if ( parseInt( count, 10 ) > 0 ) {
10584 7584 jQuery( '.frm_csv_remaining' ).html( count );
10585 7585 frmImportCsv( formID );
10586 7586 } else {
10587 - jQuery( document.getElementById( 'frm_import_message' ) ).html( frm_admin_js.import_complete ); // eslint-disable-line camelcase
7587 + jQuery( document.getElementById( 'frm_import_message' ) ).html( frm_admin_js.import_complete );
10588 7588 setTimeout( function() {
10589 7589 location.href = '?page=formidable-entries&frm_action=list&form=' + formID + '&import-message=1';
10590 7590 }, 2000 );
10591 7591 }
@@ -10590,5 +7590,21 @@
10590 7590 }, 2000 );
10591 7591 }
10592 7592 }
10593 7593 });
7594 +}
7595 +
7596 +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/Trim#Polyfill
7597 +if ( ! String.prototype.trim ) {
7598 + String.prototype.trim = function() {
7599 + return this.replace( /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '' );
7600 + };
7601 +}
7602 +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith#Polyfill
7603 +if ( ! String.prototype.startsWith ) {
7604 + Object.defineProperty( String.prototype, 'startsWith', {
7605 + value: function( search, pos ) {
7606 + pos = ! pos || pos < 0 ? 0 : +pos;
7607 + return this.substring( pos, pos + search.length ) === search;
7608 + }
7609 + });
10594 7610 }