PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / trunk
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More vtrunk
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/admin/style.js +263 -79 6.26 → trunk View file →
@@ -2,9 +2,8 @@
2 2 * This script file handles style settings in the Lite plugin.
3 3 * Pro-specific features are in the style-settings.js file in Pro.
4 4 */
5 5 ( function() {
6 - /* globals frmDom, frmAdminBuild */
7 6 'use strict';
8 7
9 8 if ( ! document.getElementById( 'frm_active_style_form' ) ) {
10 9 return;
@@ -61,11 +60,100 @@
61 60 document.body.classList.remove( 'wp-core-ui' );
62 61 document.getElementById( 'frm_style_sidebar' ).classList.add( 'wp-core-ui' );
63 62
64 63 jQuery( document ).on( 'input change', 'input[data-frmrange]', initSliderPreview );
64 +
65 + initOptionLayoutPreview();
65 66 }
66 67
67 68 /**
69 + * Sync the radio/checkbox option layout (alignment) style settings to the preview form in real time.
70 + *
71 + * The layout is applied to the front end through a container class, so changing the style setting
72 + * does not re-render the preview form. This swaps the container class on preview fields that use the
73 + * style setting. The styler preview marks those fields with .frm-default-option-align, so fields with
74 + * their own alignment override are left untouched.
75 + *
76 + * @return {void}
77 + */
78 + function initOptionLayoutPreview() {
79 + bindOptionLayoutSelect( document.getElementById( 'frm_radio_align' ), '.frm_radio' );
80 + bindOptionLayoutSelect( document.getElementById( 'frm_check_align' ), '.frm_checkbox' );
81 + }
82 +
83 + /**
84 + * Listen for changes on an option layout style setting and update the preview to match.
85 + *
86 + * @param {HTMLSelectElement|null} select The style setting dropdown.
87 + * @param {string} optionSelector The single option selector ('.frm_radio' or '.frm_checkbox').
88 + * @return {void}
89 + */
90 + function bindOptionLayoutSelect( select, optionSelector ) {
91 + if ( ! select ) {
92 + return;
93 + }
94 +
95 + select.addEventListener( 'change', () => {
96 + updatePreviewOptionLayout( optionSelector, select.value );
97 + } );
98 + }
99 +
100 + /**
101 + * Replace the alignment container class on preview fields that are using the style setting.
102 + *
103 + * @param {string} optionSelector The single option selector ('.frm_radio' or '.frm_checkbox').
104 + * @param {string} newAlign The newly selected style alignment value.
105 + * @return {void}
106 + */
107 + function updatePreviewOptionLayout( optionSelector, newAlign ) {
108 + const newClass = optionLayoutAlignToClass( newAlign );
109 +
110 + if ( ! newClass ) {
111 + return;
112 + }
113 +
114 + const activeForm = document.getElementById( 'frm_active_style_form' );
115 + if ( ! activeForm ) {
116 + return;
117 + }
118 +
119 + const alignClasses = [ 'vertical_radio', 'horizontal_radio', 'frm_two_col', 'frm_three_col', 'frm_four_col' ];
120 + const containers = new Set();
121 +
122 + activeForm.querySelectorAll( optionSelector ).forEach( option => {
123 + const container = option.closest( '.frm_form_field' );
124 +
125 + // Only fields using the style setting (no override) are marked in the styler preview.
126 + if ( container?.classList.contains( 'frm-default-option-align' ) ) {
127 + containers.add( container );
128 + }
129 + } );
130 +
131 + containers.forEach( container => {
132 + container.classList.remove( ...alignClasses );
133 + container.classList.add( newClass );
134 + } );
135 + }
136 +
137 + /**
138 + * Map an option layout style value to its front-end container class.
139 + *
140 + * @param {string} align The style alignment value.
141 + * @return {string} The matching container class.
142 + */
143 + function optionLayoutAlignToClass( align ) {
144 + if ( 'inline' === align ) {
145 + return 'horizontal_radio';
146 + }
147 +
148 + if ( 'block' === align ) {
149 + return 'vertical_radio';
150 + }
151 +
152 + return align;
153 + }
154 +
155 + /**
68 156 * Initialize the slider functionality in the style preview.
69 157 *
70 158 * @param {HTMLElement} event
71 159 * @return {void}
@@ -95,11 +183,10 @@
95 183 * @return {void}
96 184 */
97 185 function initListPage() {
98 186 document.addEventListener( 'click', handleClickEventsForListPage );
99 - // Add a timeout so Pro has a chance to add a filter first.
100 - // 0 does not always work in Google Chrome, so use 1.
101 - setTimeout( addHamburgerMenusToCards, 1 );
187 + // The dropdown options are added on the first open, so there is no longer a filter from Pro to wait for here.
188 + addHamburgerMenusToCards();
102 189 initDatepickerSample();
103 190
104 191 const enableToggle = document.getElementById( 'frm_enable_styling' );
105 192 const styleIdInput = getStyleIdInput();
@@ -255,9 +342,9 @@
255 342 * @param {Event} event
256 343 * @return {void}
257 344 */
258 345 function handleCommonClickEvents( event ) {
259 - const target = event.target;
346 + const { target } = event;
260 347
261 348 if ( 'frm_toggle_sample_form' === target.id || target.closest( '#frm_toggle_sample_form' ) ) {
262 349 toggleSampleForm();
263 350 return;
@@ -270,9 +357,8 @@
270 357 }
271 358
272 359 if ( target.classList.contains( 'frm-edit-style' ) || null !== target.closest( '.frm-edit-style' ) || 'frm_edit_style' === target.id ) {
273 360 modifyStylerUrl( target );
274 - return; // eslint-disable-line
275 361 }
276 362 }
277 363
278 364 /**
@@ -282,9 +368,9 @@
282 368 * @return {void}
283 369 */
284 370 function switchAdvancedSettingsFormAction( target ) {
285 371 const form = document.querySelector( '#frm_styling_form' );
286 - if ( null === form ) {
372 + if ( ! form ) {
287 373 return;
288 374 }
289 375 if ( target.closest( 'a#frm_style_back_to_quick_settings' ) ) {
290 376 form.action = form.action.replace( '&section=advanced-settings', '' );
@@ -322,13 +408,12 @@
322 408 * @param {Event} event
323 409 * @return {void}
324 410 */
325 411 function handleClickEventsForListPage( event ) {
326 - const target = event.target;
412 + const { target } = event;
327 413
328 414 if ( target.classList.contains( 'frm-style-card' ) || target.closest( '.frm-style-card' ) ) {
329 415 handleStyleCardClick( event );
330 - return; // eslint-disable-line
331 416 }
332 417 }
333 418
334 419 /**
@@ -338,9 +423,9 @@
338 423 * @param {Event} event
339 424 * @return {void}
340 425 */
341 426 function handleStyleCardClick( event ) {
342 - const target = event.target;
427 + const { target } = event;
343 428
344 429 if ( target.closest( '.dropdown' ) ) {
345 430 // Ignore the hamburger menu inside of the card.
346 431 return;
@@ -373,13 +458,11 @@
373 458
374 459 sampleForm.classList.remove( activeCard.dataset.classname );
375 460 sampleForm.classList.add( card.dataset.classname );
376 461
377 - if ( ! cardIsLocked ) {
378 - // Don't update the form when a locked card is clicked.
379 - styleIdInput.value = card.dataset.styleId;
380 - trackListPageChange();
381 - }
462 + // cardIsLocked is always false here due to early return above.
463 + styleIdInput.value = card.dataset.styleId;
464 + trackListPageChange();
382 465
383 466 setTimeout( enableLabelTransitions, 1 );
384 467
385 468 // We want to toggle the edit button so you can only leave the page to edit the style if it's active (to avoid unsaved changes).
@@ -565,9 +648,9 @@
565 648 return;
566 649 }
567 650
568 651 const anchor = clickTarget.hasAttribute( 'href' ) ? clickTarget : clickTarget.querySelector( 'a[href]' );
569 - anchor.setAttribute( 'href', anchor.getAttribute( 'href' ) + '&sample=1' );
652 + anchor.setAttribute( 'href', `${ anchor.getAttribute( 'href' ) }&sample=1` );
570 653 }
571 654
572 655 /**
573 656 * Add menu dropdowns to style cards dynamically on load.
@@ -587,9 +670,9 @@
587 670 if ( ! shouldAddMenuToCard( card ) ) {
588 671 return;
589 672 }
590 673
591 - card.appendChild( getHamburgerMenu( card.dataset ) );
674 + card.append( getHamburgerMenu( card.dataset ) );
592 675 }
593 676
594 677 /**
595 678 * Avoid adding a menu to an upsell card or a template card.
@@ -637,9 +720,73 @@
637 720 hamburgerMenu.setAttribute( 'data-bs-container', 'body' );
638 721 hamburgerMenu.setAttribute( 'role', 'button' );
639 722 hamburgerMenu.setAttribute( 'tabindex', 0 );
640 723
641 - const isTemplate = 'undefined' !== typeof data.templateKey;
724 + const isTemplate = data.templateKey !== undefined;
725 +
726 + const dropdownMenu = div( {
727 + // Use dropdown-menu-right to avoid an overlapping issue with the card to the right (where the # of forms would appear above the menu).
728 + className: 'frm-dropdown-menu frm-style-options-menu frm-p-1'
729 + } );
730 +
731 + const isRtl = document.body.classList.contains( 'rtl' );
732 + dropdownMenu.classList.add( `dropdown-menu-${ isRtl ? 'left' : 'right' }` );
733 +
734 + dropdownMenu.setAttribute( 'role', 'menu' );
735 +
736 + fillDropdownMenuOnFirstOpen( hamburgerMenu, dropdownMenu, data, isTemplate );
737 +
738 + return div( {
739 + className: 'dropdown frm_wrap', // The .frm_wrap class prevents a blue outline on the active dropdown trigger.
740 + children: [ hamburgerMenu, dropdownMenu ]
741 + } );
742 + }
743 +
744 + /**
745 + * Add the options to a style card dropdown the first time that dropdown is opened.
746 + *
747 + * The options are built through the frm_style_card_dropdown_options filter, and Pro registers its
748 + * callback while its own script file runs. Adding the options while the page loads raced that file,
749 + * so a request for it that was slow to come back left every card holding the Lite only options.
750 + * Waiting for the first open takes the script order out of it, since Pro has always registered the
751 + * filter by the time a card can be clicked.
752 + *
753 + * @since 6.35
754 + *
755 + * @param {HTMLElement} hamburgerMenu The dropdown trigger.
756 + * @param {HTMLElement} dropdownMenu The dropdown to add the options to.
757 + * @param {DOMStringMap} data The dataset of the style card, or an object with the style ID on the edit page.
758 + * @param {boolean} isTemplate Whether the card is for a style template.
759 + * @return {void}
760 + */
761 + function fillDropdownMenuOnFirstOpen( hamburgerMenu, dropdownMenu, data, isTemplate ) {
762 + const fillDropdownMenu = () => {
763 + if ( dropdownMenu.children.length ) {
764 + return;
765 + }
766 +
767 + const options = getDropdownMenuOptions( data, isTemplate );
768 + dropdownMenu.append( ...options.map( wrapDropdownItem ) );
769 + };
770 +
771 + // Bootstrap fires this on the trigger before it measures and positions the dropdown.
772 + hamburgerMenu.addEventListener( 'show.bs.dropdown', fillDropdownMenu );
773 +
774 + // Fall back to the click in case the dropdown is ever opened without Bootstrap. Listen in the
775 + // capture phase so the options are in place before Bootstrap's own delegated handler runs.
776 + hamburgerMenu.addEventListener( 'click', fillDropdownMenu, true );
777 + }
778 +
779 + /**
780 + * Get the options for a single style card dropdown.
781 + *
782 + * @since 6.35
783 + *
784 + * @param {DOMStringMap} data The dataset of the style card, or an object with the style ID on the edit page.
785 + * @param {boolean} isTemplate Whether the card is for a style template.
786 + * @return {Array} The dropdown options, each an object with an anchor and a type.
787 + */
788 + function getDropdownMenuOptions( data, isTemplate ) {
642 789 let dropdownMenuOptions = [];
643 790
644 791 if ( isListPage ) {
645 792 const applyOption = a( {
@@ -680,23 +827,9 @@
680 827 if ( isListPage && ! isTemplate ) {
681 828 maybeAddDuplicateUpsell( dropdownMenuOptions );
682 829 }
683 830
684 - const dropdownMenu = div( {
685 - // Use dropdown-menu-right to avoid an overlapping issue with the card to the right (where the # of forms would appear above the menu).
686 - className: 'frm-dropdown-menu frm-style-options-menu frm-p-1',
687 - children: dropdownMenuOptions.map( wrapDropdownItem )
688 - } );
689 -
690 - const isRtl = document.body.classList.contains( 'rtl' );
691 - dropdownMenu.classList.add( 'dropdown-menu-' + ( isRtl ? 'left' : 'right' ) );
692 -
693 - dropdownMenu.setAttribute( 'role', 'menu' );
694 -
695 - return div( {
696 - className: 'dropdown frm_wrap', // The .frm_wrap class prevents a blue outline on the active dropdown trigger.
697 - children: [ hamburgerMenu, dropdownMenu ]
698 - } );
831 + return dropdownMenuOptions;
699 832 }
700 833
701 834 /**
702 835 * @param {Array} dropdownMenuOptions
@@ -801,9 +934,9 @@
801 934 // Create a form so we can listen to Enter key presses that trigger a form submit event.
802 935 const form = tag(
803 936 'form',
804 937 {
805 - child: labelledTextInput( 'frm_' + context + '_style_name_input', __( 'Style name', 'formidable' ), 'style_name' )
938 + child: labelledTextInput( `frm_${ context }_style_name_input`, __( 'Style name', 'formidable' ), 'style_name' )
806 939 }
807 940 );
808 941 form.addEventListener(
809 942 'submit',
@@ -878,8 +1011,26 @@
878 1011 // The button gets disabled on an input event when the name is empty.
879 1012 return;
880 1013 }
881 1014
1015 + if ( ! styleId || '0' === String( styleId ) ) {
1016 + // A new or duplicated style has no ID yet, so there is nothing to rename on the server.
1017 + // Update the post_title input (which overrides $_GET['style_name'] on save) and the
1018 + // visible style name instead of calling the rename_style endpoint.
1019 + const postTitleInput = document.querySelector( 'input[name="frm_style_setting[post_title]"]' );
1020 + if ( postTitleInput ) {
1021 + postTitleInput.value = newStyleName;
1022 + }
1023 +
1024 + const styleNameElement = document.getElementById( 'frm_style_name' );
1025 + if ( styleNameElement ) {
1026 + styleNameElement.textContent = newStyleName;
1027 + }
1028 +
1029 + success( __( 'Style has been renamed successfully', 'formidable' ) );
1030 + return;
1031 + }
1032 +
882 1033 const formData = new FormData();
883 1034 formData.append( 'style_id', styleId );
884 1035 formData.append( 'style_name', newStyleName );
885 1036 doJsonPost( 'rename_style', formData ).then(
@@ -916,21 +1067,13 @@
916 1067 titleElement.textContent = newStyleName;
917 1068 }
918 1069
919 1070 /**
920 - * @param {string} templateKey
921 - * @return {HTMLElement} The template card element.
922 - */
923 - function getTemplateCard( templateKey ) {
924 - return document.getElementById( 'frm_template_style_cards_wrapper' ).querySelector( '.frm-style-card[data-template-key="' + templateKey + '"]' );
925 - }
926 -
927 - /**
928 1071 * @param {string} styleId
929 1072 * @return {HTMLElement} The card element.
930 1073 */
931 1074 function getCardByStyleId( styleId ) {
932 - const defaultCard = document.querySelector( '#frm_default_style_cards_wrapper > div[data-style-id="' + styleId + '"]' );
1075 + const defaultCard = document.querySelector( `#frm_default_style_cards_wrapper > div[data-style-id="${ styleId }"]` );
933 1076 if ( defaultCard ) {
934 1077 return defaultCard;
935 1078 }
936 1079 return Array.from( document.getElementById( 'frm_custom_style_cards_wrapper' ).children ).find( card => card.dataset.styleId === styleId );
@@ -941,9 +1084,9 @@
941 1084 * @param {string} iconId
942 1085 * @return {void}
943 1086 */
944 1087 function addIconToOption( option, iconId ) {
945 - const icon = frmDom.svg( { href: '#' + iconId } );
1088 + const icon = frmDom.svg( { href: `#${ iconId }` } );
946 1089 option.insertBefore( icon, option.firstChild );
947 1090 }
948 1091
949 1092 /**
@@ -1061,9 +1204,9 @@
1061 1204 defaultValues = JSON.parse( defaultValues );
1062 1205 }
1063 1206
1064 1207 for ( const key in defaultValues ) {
1065 - let targetInput = document.querySelector( 'input[name$="[' + key + ']"], select[name$="[' + key + ']"]' );
1208 + let targetInput = document.querySelector( `input[name$="[${ key }]"], select[name$="[${ key }]"]` );
1066 1209 if ( ! targetInput ) {
1067 1210 continue;
1068 1211 }
1069 1212
@@ -1068,9 +1211,9 @@
1068 1211 }
1069 1212
1070 1213 if ( 'radio' === targetInput.getAttribute( 'type' ) ) {
1071 1214 // Reset the repeater icon dropdown.
1072 - targetInput = document.querySelector( 'input[name$="[' + key + ']"][value="' + defaultValues[ key ] + '"]' );
1215 + targetInput = document.querySelector( `input[name$="[${ key }]"][value="${ defaultValues[ key ] }"]` );
1073 1216 if ( targetInput ) {
1074 1217 targetInput.checked = true;
1075 1218 jQuery( targetInput ).trigger( 'change' );
1076 1219 }
@@ -1119,21 +1262,21 @@
1119 1262
1120 1263 const newStyle = document.createElement( 'link' );
1121 1264 newStyle.rel = 'stylesheet';
1122 1265 newStyle.type = 'text/css';
1123 - newStyle.href = style.href + '&key=' + getAutoId(); // Make the URL unique so the old stylesheet doesn't get picked up by cache.
1266 + newStyle.href = `${ style.href }&key=${ getAutoId() }`; // Make the URL unique so the old stylesheet doesn't get picked up by cache.
1124 1267
1125 1268 // Listen for the new style to load before removing the old style to avoid having no styles while the new style is loading.
1126 1269 newStyle.addEventListener(
1127 1270 'load',
1128 1271 () => {
1129 - style.parentNode.removeChild( style );
1272 + style.remove();
1130 1273 newStyle.id = 'frm-custom-theme-css'; // Assign the old ID to the new style so it can be removed in the next reset action.
1131 1274 }
1132 1275 );
1133 1276
1134 1277 const head = document.getElementsByTagName( 'HEAD' )[ 0 ];
1135 - head.appendChild( newStyle );
1278 + head.append( newStyle );
1136 1279 }
1137 1280
1138 1281 /**
1139 1282 * @return {number} The auto ID.
@@ -1149,9 +1292,9 @@
1149 1292 * @return {HTMLElement} The dropdown item element.
1150 1293 */
1151 1294 function wrapDropdownItem( { anchor, type } ) {
1152 1295 return div( {
1153 - className: 'dropdown-item frm-' + type + '-style',
1296 + className: `dropdown-item frm-${ type }-style`,
1154 1297 child: anchor
1155 1298 } );
1156 1299 }
1157 1300
@@ -1179,29 +1322,86 @@
1179 1322 [ 'frm_field_height', 'frm_field_font_size', 'frm_field_pad' ].forEach( selector => {
1180 1323 document.getElementById( selector ).addEventListener( 'change', debouncedTextSquishCheck );
1181 1324 } );
1182 1325
1183 - jQuery( 'input.hex' ).wpColorPicker( {
1184 - change: function( event, ui ) {
1185 - let color = jQuery( this ).wpColorPicker( 'color' );
1326 + function detectColorFormat( value ) {
1327 + if ( value.startsWith( 'rgba' ) ) {
1328 + return 'rgba';
1329 + }
1330 + if ( value.startsWith( 'rgb' ) ) {
1331 + return 'rgb';
1332 + }
1333 + if ( value.startsWith( 'hsla' ) ) {
1334 + return 'hsla';
1335 + }
1336 + if ( value.startsWith( 'hsl' ) ) {
1337 + return 'hsl';
1338 + }
1339 + return 'hex';
1340 + }
1341 +
1342 + const nativeInputValueDescriptor = Object.getOwnPropertyDescriptor( HTMLInputElement.prototype, 'value' );
1343 +
1344 + jQuery( 'input.hex' ).each( function() {
1345 + this.dataset.colorFormat = detectColorFormat( this.value );
1346 +
1347 + // Prevent iris from overwriting non-hex formats with hex during color picking.
1348 + const input = this;
1349 + Object.defineProperty( input, 'value', {
1350 + get() {
1351 + return nativeInputValueDescriptor.get.call( this );
1352 + },
1353 + set( val ) {
1354 + const format = input.dataset.colorFormat;
1355 + if ( format && 'hex' !== format && /^#[0-9a-f]{3,8}$/i.test( val ) ) {
1356 + return;
1357 + }
1358 + nativeInputValueDescriptor.set.call( this, val );
1359 + },
1360 + configurable: true
1361 + } );
1362 + } ).on( 'keyup', function() {
1363 + const newFormat = detectColorFormat( this.value );
1364 + if ( this.dataset.colorFormat !== newFormat ) {
1365 + this.dataset.colorFormat = newFormat;
1366 + const container = this.closest( '.wp-picker-container' );
1367 + if ( container ) {
1368 + container.querySelector( '.wp-color-result-text' ).textContent = this.value;
1369 + }
1370 + debouncedColorChange( { target: this }, this.value );
1371 + }
1372 + } ).wpColorPicker( {
1373 + change( event, ui ) {
1374 + const input = event.target;
1375 + const format = input.dataset.colorFormat || 'hex';
1376 + let color;
1377 +
1186 1378 trackUnsavedChange();
1379 +
1187 1380 if ( ui.color._alpha < 1 ) {
1188 - // If there's transparency, use RGBA
1381 + input.dataset.colorFormat = 'rgba';
1189 1382 color = ui.color.toCSS( 'rgba' );
1383 + } else if ( 'hex' === format ) {
1384 + color = ui.color.toString();
1385 + } else {
1386 + color = ui.color.toCSS( format );
1190 1387 }
1388 +
1191 1389 debouncedColorChange( event, color );
1192 1390
1193 - if ( null !== event.target.getAttribute( 'data-alpha-color-type' ) ) {
1391 + input.value = color;
1392 +
1393 + if ( null !== input.getAttribute( 'data-alpha-color-type' ) ) {
1194 1394 debouncedPreviewUpdate();
1195 1395 return;
1196 1396 }
1197 1397
1198 - jQuery( event.target ).val( color ).trigger( 'change' );
1398 + debouncedPreviewUpdate();
1199 1399 }
1200 1400 } );
1201 1401 jQuery( '.wp-color-result-text' ).text( function( _, oldText ) {
1202 1402 const container = jQuery( this ).closest( '.wp-picker-container' );
1203 - if ( 'undefined' !== typeof container && container[ 0 ].parentElement.classList.contains( 'frm-colorpicker' ) ) {
1403 + if ( container !== undefined && container[ 0 ].parentElement.classList.contains( 'frm-colorpicker' ) ) {
1204 1404 return container[ 0 ].querySelector( '.wp-color-picker' ).value;
1205 1405 }
1206 1406 return oldText === 'Select Color' ? 'Select' : oldText;
1207 1407 } );
@@ -1250,9 +1450,9 @@
1250 1450 * @return {void}
1251 1451 */
1252 1452 function handleChangeStylingSuccess( css ) {
1253 1453 // Validate the string response. A valid output will include rules with .with_frm_style
1254 - if ( -1 === css.indexOf( '.with_frm_style' ) ) {
1454 + if ( ! css.includes( '.with_frm_style' ) ) {
1255 1455 // Handle error (possibly a permission error, or an outdated nonce).
1256 1456 alert( css );
1257 1457 return;
1258 1458 }
@@ -1312,9 +1512,9 @@
1312 1512 if ( select ) {
1313 1513 select.value = radio.value;
1314 1514 }
1315 1515
1316 - jQuery( btnGrp ).children( 'button' ).html( radio.nextElementSibling.innerHTML + ' <b class="caret"></b>' );
1516 + jQuery( btnGrp ).children( 'button' ).html( `${ radio.nextElementSibling.innerHTML } <b class="caret"></b>` );
1317 1517
1318 1518 const activeItem = btnGrp.querySelector( '.dropdown-item.active' );
1319 1519 if ( activeItem ) {
1320 1520 activeItem.classList.remove( 'active' );
@@ -1334,24 +1534,8 @@
1334 1534 }
1335 1535 }
1336 1536
1337 1537 /**
1338 - * @param {Event} event
1339 - */
1340 - function maybeCollapseSettings( event ) {
1341 - let expanded;
1342 - const sectionParent = event.target.parentElement;
1343 - if ( event.type === 'keydown' ) {
1344 - expanded = sectionParent.classList.toggle( 'open' );
1345 - jQuery( sectionParent.querySelector( '.accordion-section-content' ) ).toggle( ! expanded ).slideToggle( 150 ); // Animate toggle as in click/enter.
1346 - } else {
1347 - expanded = sectionParent.classList.contains( 'open' );
1348 - }
1349 -
1350 - event.target.setAttribute( 'aria-expanded', expanded );
1351 - }
1352 -
1353 - /**
1354 1538 * @param {HTMLElement} input
1355 1539 * @param {HTMLElement} container
1356 1540 * @return {void}
1357 1541 */
@@ -1401,9 +1585,9 @@
1401 1585 * @return {void}
1402 1586 */
1403 1587 function setPosClass() {
1404 1588 /*jshint validthis:true */
1405 - let value = this.value;
1589 + let { value } = this;
1406 1590 if ( value === 'none' ) {
1407 1591 value = 'top';
1408 1592 } else if ( value === 'no_label' ) {
1409 1593 value = 'none';
@@ -1414,9 +1598,9 @@
1414 1598 const shouldForceTopStyling = 'inside' === value && ( ! input || 'hidden' === input.type ); // We do not want file upload to use floating labels, or inline datepickers, which both use hidden inputs.
1415 1599 const currentValue = shouldForceTopStyling ? 'top' : value;
1416 1600
1417 1601 container.classList.remove( 'frm_top_container', 'frm_left_container', 'frm_right_container', 'frm_none_container', 'frm_inside_container' );
1418 - container.classList.add( 'frm_' + currentValue + '_container' );
1602 + container.classList.add( `frm_${ currentValue }_container` );
1419 1603
1420 1604 if ( 'inside' === currentValue ) {
1421 1605 checkFloatingLabelsForStyles( input, container );
1422 1606 }
@@ -1444,9 +1628,9 @@
1444 1628 *
1445 1629 * @return {void}
1446 1630 */
1447 1631 function fillMissingSignatureValidationFunction() {
1448 - if ( 'undefined' === typeof window.__FRMSIG || 'undefined' !== typeof window.frmFrontForm ) {
1632 + if ( window.__FRMSIG === undefined || window.frmFrontForm !== undefined ) {
1449 1633 return;
1450 1634 }
1451 1635
1452 1636 window.frmFrontForm = { validateFormSubmit: () => {} };
@@ -1485,9 +1669,9 @@
1485 1669 }
1486 1670
1487 1671 // Function to change the color of a select element
1488 1672 const changeSelectColor = select => {
1489 - if ( select.options[ select.selectedIndex ] && select.options[ select.selectedIndex ].classList.contains( 'frm-select-placeholder' ) ) {
1673 + if ( select.options[ select.selectedIndex ]?.classList.contains( 'frm-select-placeholder' ) ) {
1490 1674 select.style.setProperty( 'color', textColorDisabled, 'important' );
1491 1675 } else {
1492 1676 select.style.color = '';
1493 1677 }