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 +260 -74 6.27 → 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;
@@ -281,9 +368,9 @@
281 368 * @return {void}
282 369 */
283 370 function switchAdvancedSettingsFormAction( target ) {
284 371 const form = document.querySelector( '#frm_styling_form' );
285 - if ( null === form ) {
372 + if ( ! form ) {
286 373 return;
287 374 }
288 375 if ( target.closest( 'a#frm_style_back_to_quick_settings' ) ) {
289 376 form.action = form.action.replace( '&section=advanced-settings', '' );
@@ -321,9 +408,9 @@
321 408 * @param {Event} event
322 409 * @return {void}
323 410 */
324 411 function handleClickEventsForListPage( event ) {
325 - const target = event.target;
412 + const { target } = event;
326 413
327 414 if ( target.classList.contains( 'frm-style-card' ) || target.closest( '.frm-style-card' ) ) {
328 415 handleStyleCardClick( event );
329 416 }
@@ -336,9 +423,9 @@
336 423 * @param {Event} event
337 424 * @return {void}
338 425 */
339 426 function handleStyleCardClick( event ) {
340 - const target = event.target;
427 + const { target } = event;
341 428
342 429 if ( target.closest( '.dropdown' ) ) {
343 430 // Ignore the hamburger menu inside of the card.
344 431 return;
@@ -371,13 +458,11 @@
371 458
372 459 sampleForm.classList.remove( activeCard.dataset.classname );
373 460 sampleForm.classList.add( card.dataset.classname );
374 461
375 - if ( ! cardIsLocked ) {
376 - // Don't update the form when a locked card is clicked.
377 - styleIdInput.value = card.dataset.styleId;
378 - trackListPageChange();
379 - }
462 + // cardIsLocked is always false here due to early return above.
463 + styleIdInput.value = card.dataset.styleId;
464 + trackListPageChange();
380 465
381 466 setTimeout( enableLabelTransitions, 1 );
382 467
383 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).
@@ -563,9 +648,9 @@
563 648 return;
564 649 }
565 650
566 651 const anchor = clickTarget.hasAttribute( 'href' ) ? clickTarget : clickTarget.querySelector( 'a[href]' );
567 - anchor.setAttribute( 'href', anchor.getAttribute( 'href' ) + '&sample=1' );
652 + anchor.setAttribute( 'href', `${ anchor.getAttribute( 'href' ) }&sample=1` );
568 653 }
569 654
570 655 /**
571 656 * Add menu dropdowns to style cards dynamically on load.
@@ -635,9 +720,73 @@
635 720 hamburgerMenu.setAttribute( 'data-bs-container', 'body' );
636 721 hamburgerMenu.setAttribute( 'role', 'button' );
637 722 hamburgerMenu.setAttribute( 'tabindex', 0 );
638 723
639 - 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 ) {
640 789 let dropdownMenuOptions = [];
641 790
642 791 if ( isListPage ) {
643 792 const applyOption = a( {
@@ -678,23 +827,9 @@
678 827 if ( isListPage && ! isTemplate ) {
679 828 maybeAddDuplicateUpsell( dropdownMenuOptions );
680 829 }
681 830
682 - const dropdownMenu = div( {
683 - // Use dropdown-menu-right to avoid an overlapping issue with the card to the right (where the # of forms would appear above the menu).
684 - className: 'frm-dropdown-menu frm-style-options-menu frm-p-1',
685 - children: dropdownMenuOptions.map( wrapDropdownItem )
686 - } );
687 -
688 - const isRtl = document.body.classList.contains( 'rtl' );
689 - dropdownMenu.classList.add( 'dropdown-menu-' + ( isRtl ? 'left' : 'right' ) );
690 -
691 - dropdownMenu.setAttribute( 'role', 'menu' );
692 -
693 - return div( {
694 - className: 'dropdown frm_wrap', // The .frm_wrap class prevents a blue outline on the active dropdown trigger.
695 - children: [ hamburgerMenu, dropdownMenu ]
696 - } );
831 + return dropdownMenuOptions;
697 832 }
698 833
699 834 /**
700 835 * @param {Array} dropdownMenuOptions
@@ -799,9 +934,9 @@
799 934 // Create a form so we can listen to Enter key presses that trigger a form submit event.
800 935 const form = tag(
801 936 'form',
802 937 {
803 - 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' )
804 939 }
805 940 );
806 941 form.addEventListener(
807 942 'submit',
@@ -876,8 +1011,26 @@
876 1011 // The button gets disabled on an input event when the name is empty.
877 1012 return;
878 1013 }
879 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 +
880 1033 const formData = new FormData();
881 1034 formData.append( 'style_id', styleId );
882 1035 formData.append( 'style_name', newStyleName );
883 1036 doJsonPost( 'rename_style', formData ).then(
@@ -914,21 +1067,13 @@
914 1067 titleElement.textContent = newStyleName;
915 1068 }
916 1069
917 1070 /**
918 - * @param {string} templateKey
919 - * @return {HTMLElement} The template card element.
920 - */
921 - function getTemplateCard( templateKey ) {
922 - return document.getElementById( 'frm_template_style_cards_wrapper' ).querySelector( '.frm-style-card[data-template-key="' + templateKey + '"]' );
923 - }
924 -
925 - /**
926 1071 * @param {string} styleId
927 1072 * @return {HTMLElement} The card element.
928 1073 */
929 1074 function getCardByStyleId( styleId ) {
930 - 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 }"]` );
931 1076 if ( defaultCard ) {
932 1077 return defaultCard;
933 1078 }
934 1079 return Array.from( document.getElementById( 'frm_custom_style_cards_wrapper' ).children ).find( card => card.dataset.styleId === styleId );
@@ -939,9 +1084,9 @@
939 1084 * @param {string} iconId
940 1085 * @return {void}
941 1086 */
942 1087 function addIconToOption( option, iconId ) {
943 - const icon = frmDom.svg( { href: '#' + iconId } );
1088 + const icon = frmDom.svg( { href: `#${ iconId }` } );
944 1089 option.insertBefore( icon, option.firstChild );
945 1090 }
946 1091
947 1092 /**
@@ -1059,9 +1204,9 @@
1059 1204 defaultValues = JSON.parse( defaultValues );
1060 1205 }
1061 1206
1062 1207 for ( const key in defaultValues ) {
1063 - let targetInput = document.querySelector( 'input[name$="[' + key + ']"], select[name$="[' + key + ']"]' );
1208 + let targetInput = document.querySelector( `input[name$="[${ key }]"], select[name$="[${ key }]"]` );
1064 1209 if ( ! targetInput ) {
1065 1210 continue;
1066 1211 }
1067 1212
@@ -1066,9 +1211,9 @@
1066 1211 }
1067 1212
1068 1213 if ( 'radio' === targetInput.getAttribute( 'type' ) ) {
1069 1214 // Reset the repeater icon dropdown.
1070 - targetInput = document.querySelector( 'input[name$="[' + key + ']"][value="' + defaultValues[ key ] + '"]' );
1215 + targetInput = document.querySelector( `input[name$="[${ key }]"][value="${ defaultValues[ key ] }"]` );
1071 1216 if ( targetInput ) {
1072 1217 targetInput.checked = true;
1073 1218 jQuery( targetInput ).trigger( 'change' );
1074 1219 }
@@ -1117,9 +1262,9 @@
1117 1262
1118 1263 const newStyle = document.createElement( 'link' );
1119 1264 newStyle.rel = 'stylesheet';
1120 1265 newStyle.type = 'text/css';
1121 - 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.
1122 1267
1123 1268 // Listen for the new style to load before removing the old style to avoid having no styles while the new style is loading.
1124 1269 newStyle.addEventListener(
1125 1270 'load',
@@ -1147,9 +1292,9 @@
1147 1292 * @return {HTMLElement} The dropdown item element.
1148 1293 */
1149 1294 function wrapDropdownItem( { anchor, type } ) {
1150 1295 return div( {
1151 - className: 'dropdown-item frm-' + type + '-style',
1296 + className: `dropdown-item frm-${ type }-style`,
1152 1297 child: anchor
1153 1298 } );
1154 1299 }
1155 1300
@@ -1177,29 +1322,86 @@
1177 1322 [ 'frm_field_height', 'frm_field_font_size', 'frm_field_pad' ].forEach( selector => {
1178 1323 document.getElementById( selector ).addEventListener( 'change', debouncedTextSquishCheck );
1179 1324 } );
1180 1325
1181 - jQuery( 'input.hex' ).wpColorPicker( {
1182 - change: function( event, ui ) {
1183 - 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 +
1184 1378 trackUnsavedChange();
1379 +
1185 1380 if ( ui.color._alpha < 1 ) {
1186 - // If there's transparency, use RGBA
1381 + input.dataset.colorFormat = 'rgba';
1187 1382 color = ui.color.toCSS( 'rgba' );
1383 + } else if ( 'hex' === format ) {
1384 + color = ui.color.toString();
1385 + } else {
1386 + color = ui.color.toCSS( format );
1188 1387 }
1388 +
1189 1389 debouncedColorChange( event, color );
1190 1390
1191 - if ( null !== event.target.getAttribute( 'data-alpha-color-type' ) ) {
1391 + input.value = color;
1392 +
1393 + if ( null !== input.getAttribute( 'data-alpha-color-type' ) ) {
1192 1394 debouncedPreviewUpdate();
1193 1395 return;
1194 1396 }
1195 1397
1196 - jQuery( event.target ).val( color ).trigger( 'change' );
1398 + debouncedPreviewUpdate();
1197 1399 }
1198 1400 } );
1199 1401 jQuery( '.wp-color-result-text' ).text( function( _, oldText ) {
1200 1402 const container = jQuery( this ).closest( '.wp-picker-container' );
1201 - if ( 'undefined' !== typeof container && container[ 0 ].parentElement.classList.contains( 'frm-colorpicker' ) ) {
1403 + if ( container !== undefined && container[ 0 ].parentElement.classList.contains( 'frm-colorpicker' ) ) {
1202 1404 return container[ 0 ].querySelector( '.wp-color-picker' ).value;
1203 1405 }
1204 1406 return oldText === 'Select Color' ? 'Select' : oldText;
1205 1407 } );
@@ -1248,9 +1450,9 @@
1248 1450 * @return {void}
1249 1451 */
1250 1452 function handleChangeStylingSuccess( css ) {
1251 1453 // Validate the string response. A valid output will include rules with .with_frm_style
1252 - if ( -1 === css.indexOf( '.with_frm_style' ) ) {
1454 + if ( ! css.includes( '.with_frm_style' ) ) {
1253 1455 // Handle error (possibly a permission error, or an outdated nonce).
1254 1456 alert( css );
1255 1457 return;
1256 1458 }
@@ -1310,9 +1512,9 @@
1310 1512 if ( select ) {
1311 1513 select.value = radio.value;
1312 1514 }
1313 1515
1314 - 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>` );
1315 1517
1316 1518 const activeItem = btnGrp.querySelector( '.dropdown-item.active' );
1317 1519 if ( activeItem ) {
1318 1520 activeItem.classList.remove( 'active' );
@@ -1332,24 +1534,8 @@
1332 1534 }
1333 1535 }
1334 1536
1335 1537 /**
1336 - * @param {Event} event
1337 - */
1338 - function maybeCollapseSettings( event ) {
1339 - let expanded;
1340 - const sectionParent = event.target.parentElement;
1341 - if ( event.type === 'keydown' ) {
1342 - expanded = sectionParent.classList.toggle( 'open' );
1343 - jQuery( sectionParent.querySelector( '.accordion-section-content' ) ).toggle( ! expanded ).slideToggle( 150 ); // Animate toggle as in click/enter.
1344 - } else {
1345 - expanded = sectionParent.classList.contains( 'open' );
1346 - }
1347 -
1348 - event.target.setAttribute( 'aria-expanded', expanded );
1349 - }
1350 -
1351 - /**
1352 1538 * @param {HTMLElement} input
1353 1539 * @param {HTMLElement} container
1354 1540 * @return {void}
1355 1541 */
@@ -1399,9 +1585,9 @@
1399 1585 * @return {void}
1400 1586 */
1401 1587 function setPosClass() {
1402 1588 /*jshint validthis:true */
1403 - let value = this.value;
1589 + let { value } = this;
1404 1590 if ( value === 'none' ) {
1405 1591 value = 'top';
1406 1592 } else if ( value === 'no_label' ) {
1407 1593 value = 'none';
@@ -1412,9 +1598,9 @@
1412 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.
1413 1599 const currentValue = shouldForceTopStyling ? 'top' : value;
1414 1600
1415 1601 container.classList.remove( 'frm_top_container', 'frm_left_container', 'frm_right_container', 'frm_none_container', 'frm_inside_container' );
1416 - container.classList.add( 'frm_' + currentValue + '_container' );
1602 + container.classList.add( `frm_${ currentValue }_container` );
1417 1603
1418 1604 if ( 'inside' === currentValue ) {
1419 1605 checkFloatingLabelsForStyles( input, container );
1420 1606 }
@@ -1442,9 +1628,9 @@
1442 1628 *
1443 1629 * @return {void}
1444 1630 */
1445 1631 function fillMissingSignatureValidationFunction() {
1446 - if ( 'undefined' === typeof window.__FRMSIG || 'undefined' !== typeof window.frmFrontForm ) {
1632 + if ( window.__FRMSIG === undefined || window.frmFrontForm !== undefined ) {
1447 1633 return;
1448 1634 }
1449 1635
1450 1636 window.frmFrontForm = { validateFormSubmit: () => {} };
@@ -1483,9 +1669,9 @@
1483 1669 }
1484 1670
1485 1671 // Function to change the color of a select element
1486 1672 const changeSelectColor = select => {
1487 - 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' ) ) {
1488 1674 select.style.setProperty( 'color', textColorDisabled, 'important' );
1489 1675 } else {
1490 1676 select.style.color = '';
1491 1677 }