| @@ -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( '§ion=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; |
| @@ -561,9 +648,9 @@ | ||
| 561 | 648 | return; |
| 562 | 649 | } |
| 563 | 650 | |
| 564 | 651 | const anchor = clickTarget.hasAttribute( 'href' ) ? clickTarget : clickTarget.querySelector( 'a[href]' ); |
| 565 | - anchor.setAttribute( 'href', anchor.getAttribute( 'href' ) + '&sample=1' ); | |
| 652 | + anchor.setAttribute( 'href', `${ anchor.getAttribute( 'href' ) }&sample=1` ); | |
| 566 | 653 | } |
| 567 | 654 | |
| 568 | 655 | /** |
| 569 | 656 | * Add menu dropdowns to style cards dynamically on load. |
| @@ -633,9 +720,73 @@ | ||
| 633 | 720 | hamburgerMenu.setAttribute( 'data-bs-container', 'body' ); |
| 634 | 721 | hamburgerMenu.setAttribute( 'role', 'button' ); |
| 635 | 722 | hamburgerMenu.setAttribute( 'tabindex', 0 ); |
| 636 | 723 | |
| 637 | - 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 ) { | |
| 638 | 789 | let dropdownMenuOptions = []; |
| 639 | 790 | |
| 640 | 791 | if ( isListPage ) { |
| 641 | 792 | const applyOption = a( { |
| @@ -676,23 +827,9 @@ | ||
| 676 | 827 | if ( isListPage && ! isTemplate ) { |
| 677 | 828 | maybeAddDuplicateUpsell( dropdownMenuOptions ); |
| 678 | 829 | } |
| 679 | 830 | |
| 680 | - const dropdownMenu = div( { | |
| 681 | - // Use dropdown-menu-right to avoid an overlapping issue with the card to the right (where the # of forms would appear above the menu). | |
| 682 | - className: 'frm-dropdown-menu frm-style-options-menu frm-p-1', | |
| 683 | - children: dropdownMenuOptions.map( wrapDropdownItem ) | |
| 684 | - } ); | |
| 685 | - | |
| 686 | - const isRtl = document.body.classList.contains( 'rtl' ); | |
| 687 | - dropdownMenu.classList.add( 'dropdown-menu-' + ( isRtl ? 'left' : 'right' ) ); | |
| 688 | - | |
| 689 | - dropdownMenu.setAttribute( 'role', 'menu' ); | |
| 690 | - | |
| 691 | - return div( { | |
| 692 | - className: 'dropdown frm_wrap', // The .frm_wrap class prevents a blue outline on the active dropdown trigger. | |
| 693 | - children: [ hamburgerMenu, dropdownMenu ] | |
| 694 | - } ); | |
| 831 | + return dropdownMenuOptions; | |
| 695 | 832 | } |
| 696 | 833 | |
| 697 | 834 | /** |
| 698 | 835 | * @param {Array} dropdownMenuOptions |
| @@ -797,9 +934,9 @@ | ||
| 797 | 934 | // Create a form so we can listen to Enter key presses that trigger a form submit event. |
| 798 | 935 | const form = tag( |
| 799 | 936 | 'form', |
| 800 | 937 | { |
| 801 | - 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' ) | |
| 802 | 939 | } |
| 803 | 940 | ); |
| 804 | 941 | form.addEventListener( |
| 805 | 942 | 'submit', |
| @@ -874,8 +1011,26 @@ | ||
| 874 | 1011 | // The button gets disabled on an input event when the name is empty. |
| 875 | 1012 | return; |
| 876 | 1013 | } |
| 877 | 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 | + | |
| 878 | 1033 | const formData = new FormData(); |
| 879 | 1034 | formData.append( 'style_id', styleId ); |
| 880 | 1035 | formData.append( 'style_name', newStyleName ); |
| 881 | 1036 | doJsonPost( 'rename_style', formData ).then( |
| @@ -916,9 +1071,9 @@ | ||
| 916 | 1071 | * @param {string} styleId |
| 917 | 1072 | * @return {HTMLElement} The card element. |
| 918 | 1073 | */ |
| 919 | 1074 | function getCardByStyleId( styleId ) { |
| 920 | - 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 }"]` ); | |
| 921 | 1076 | if ( defaultCard ) { |
| 922 | 1077 | return defaultCard; |
| 923 | 1078 | } |
| 924 | 1079 | return Array.from( document.getElementById( 'frm_custom_style_cards_wrapper' ).children ).find( card => card.dataset.styleId === styleId ); |
| @@ -929,9 +1084,9 @@ | ||
| 929 | 1084 | * @param {string} iconId |
| 930 | 1085 | * @return {void} |
| 931 | 1086 | */ |
| 932 | 1087 | function addIconToOption( option, iconId ) { |
| 933 | - const icon = frmDom.svg( { href: '#' + iconId } ); | |
| 1088 | + const icon = frmDom.svg( { href: `#${ iconId }` } ); | |
| 934 | 1089 | option.insertBefore( icon, option.firstChild ); |
| 935 | 1090 | } |
| 936 | 1091 | |
| 937 | 1092 | /** |
| @@ -1049,9 +1204,9 @@ | ||
| 1049 | 1204 | defaultValues = JSON.parse( defaultValues ); |
| 1050 | 1205 | } |
| 1051 | 1206 | |
| 1052 | 1207 | for ( const key in defaultValues ) { |
| 1053 | - let targetInput = document.querySelector( 'input[name$="[' + key + ']"], select[name$="[' + key + ']"]' ); | |
| 1208 | + let targetInput = document.querySelector( `input[name$="[${ key }]"], select[name$="[${ key }]"]` ); | |
| 1054 | 1209 | if ( ! targetInput ) { |
| 1055 | 1210 | continue; |
| 1056 | 1211 | } |
| 1057 | 1212 | |
| @@ -1056,9 +1211,9 @@ | ||
| 1056 | 1211 | } |
| 1057 | 1212 | |
| 1058 | 1213 | if ( 'radio' === targetInput.getAttribute( 'type' ) ) { |
| 1059 | 1214 | // Reset the repeater icon dropdown. |
| 1060 | - targetInput = document.querySelector( 'input[name$="[' + key + ']"][value="' + defaultValues[ key ] + '"]' ); | |
| 1215 | + targetInput = document.querySelector( `input[name$="[${ key }]"][value="${ defaultValues[ key ] }"]` ); | |
| 1061 | 1216 | if ( targetInput ) { |
| 1062 | 1217 | targetInput.checked = true; |
| 1063 | 1218 | jQuery( targetInput ).trigger( 'change' ); |
| 1064 | 1219 | } |
| @@ -1107,9 +1262,9 @@ | ||
| 1107 | 1262 | |
| 1108 | 1263 | const newStyle = document.createElement( 'link' ); |
| 1109 | 1264 | newStyle.rel = 'stylesheet'; |
| 1110 | 1265 | newStyle.type = 'text/css'; |
| 1111 | - 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. | |
| 1112 | 1267 | |
| 1113 | 1268 | // Listen for the new style to load before removing the old style to avoid having no styles while the new style is loading. |
| 1114 | 1269 | newStyle.addEventListener( |
| 1115 | 1270 | 'load', |
| @@ -1137,9 +1292,9 @@ | ||
| 1137 | 1292 | * @return {HTMLElement} The dropdown item element. |
| 1138 | 1293 | */ |
| 1139 | 1294 | function wrapDropdownItem( { anchor, type } ) { |
| 1140 | 1295 | return div( { |
| 1141 | - className: 'dropdown-item frm-' + type + '-style', | |
| 1296 | + className: `dropdown-item frm-${ type }-style`, | |
| 1142 | 1297 | child: anchor |
| 1143 | 1298 | } ); |
| 1144 | 1299 | } |
| 1145 | 1300 | |
| @@ -1167,29 +1322,86 @@ | ||
| 1167 | 1322 | [ 'frm_field_height', 'frm_field_font_size', 'frm_field_pad' ].forEach( selector => { |
| 1168 | 1323 | document.getElementById( selector ).addEventListener( 'change', debouncedTextSquishCheck ); |
| 1169 | 1324 | } ); |
| 1170 | 1325 | |
| 1171 | - jQuery( 'input.hex' ).wpColorPicker( { | |
| 1172 | - change: function( event, ui ) { | |
| 1173 | - 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 | + | |
| 1174 | 1378 | trackUnsavedChange(); |
| 1379 | + | |
| 1175 | 1380 | if ( ui.color._alpha < 1 ) { |
| 1176 | - // If there's transparency, use RGBA | |
| 1381 | + input.dataset.colorFormat = 'rgba'; | |
| 1177 | 1382 | color = ui.color.toCSS( 'rgba' ); |
| 1383 | + } else if ( 'hex' === format ) { | |
| 1384 | + color = ui.color.toString(); | |
| 1385 | + } else { | |
| 1386 | + color = ui.color.toCSS( format ); | |
| 1178 | 1387 | } |
| 1388 | + | |
| 1179 | 1389 | debouncedColorChange( event, color ); |
| 1180 | 1390 | |
| 1181 | - if ( null !== event.target.getAttribute( 'data-alpha-color-type' ) ) { | |
| 1391 | + input.value = color; | |
| 1392 | + | |
| 1393 | + if ( null !== input.getAttribute( 'data-alpha-color-type' ) ) { | |
| 1182 | 1394 | debouncedPreviewUpdate(); |
| 1183 | 1395 | return; |
| 1184 | 1396 | } |
| 1185 | 1397 | |
| 1186 | - jQuery( event.target ).val( color ).trigger( 'change' ); | |
| 1398 | + debouncedPreviewUpdate(); | |
| 1187 | 1399 | } |
| 1188 | 1400 | } ); |
| 1189 | 1401 | jQuery( '.wp-color-result-text' ).text( function( _, oldText ) { |
| 1190 | 1402 | const container = jQuery( this ).closest( '.wp-picker-container' ); |
| 1191 | - if ( 'undefined' !== typeof container && container[ 0 ].parentElement.classList.contains( 'frm-colorpicker' ) ) { | |
| 1403 | + if ( container !== undefined && container[ 0 ].parentElement.classList.contains( 'frm-colorpicker' ) ) { | |
| 1192 | 1404 | return container[ 0 ].querySelector( '.wp-color-picker' ).value; |
| 1193 | 1405 | } |
| 1194 | 1406 | return oldText === 'Select Color' ? 'Select' : oldText; |
| 1195 | 1407 | } ); |
| @@ -1238,9 +1450,9 @@ | ||
| 1238 | 1450 | * @return {void} |
| 1239 | 1451 | */ |
| 1240 | 1452 | function handleChangeStylingSuccess( css ) { |
| 1241 | 1453 | // Validate the string response. A valid output will include rules with .with_frm_style |
| 1242 | - if ( -1 === css.indexOf( '.with_frm_style' ) ) { | |
| 1454 | + if ( ! css.includes( '.with_frm_style' ) ) { | |
| 1243 | 1455 | // Handle error (possibly a permission error, or an outdated nonce). |
| 1244 | 1456 | alert( css ); |
| 1245 | 1457 | return; |
| 1246 | 1458 | } |
| @@ -1300,9 +1512,9 @@ | ||
| 1300 | 1512 | if ( select ) { |
| 1301 | 1513 | select.value = radio.value; |
| 1302 | 1514 | } |
| 1303 | 1515 | |
| 1304 | - 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>` ); | |
| 1305 | 1517 | |
| 1306 | 1518 | const activeItem = btnGrp.querySelector( '.dropdown-item.active' ); |
| 1307 | 1519 | if ( activeItem ) { |
| 1308 | 1520 | activeItem.classList.remove( 'active' ); |
| @@ -1373,9 +1585,9 @@ | ||
| 1373 | 1585 | * @return {void} |
| 1374 | 1586 | */ |
| 1375 | 1587 | function setPosClass() { |
| 1376 | 1588 | /*jshint validthis:true */ |
| 1377 | - let value = this.value; | |
| 1589 | + let { value } = this; | |
| 1378 | 1590 | if ( value === 'none' ) { |
| 1379 | 1591 | value = 'top'; |
| 1380 | 1592 | } else if ( value === 'no_label' ) { |
| 1381 | 1593 | value = 'none'; |
| @@ -1386,9 +1598,9 @@ | ||
| 1386 | 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. |
| 1387 | 1599 | const currentValue = shouldForceTopStyling ? 'top' : value; |
| 1388 | 1600 | |
| 1389 | 1601 | container.classList.remove( 'frm_top_container', 'frm_left_container', 'frm_right_container', 'frm_none_container', 'frm_inside_container' ); |
| 1390 | - container.classList.add( 'frm_' + currentValue + '_container' ); | |
| 1602 | + container.classList.add( `frm_${ currentValue }_container` ); | |
| 1391 | 1603 | |
| 1392 | 1604 | if ( 'inside' === currentValue ) { |
| 1393 | 1605 | checkFloatingLabelsForStyles( input, container ); |
| 1394 | 1606 | } |
| @@ -1416,9 +1628,9 @@ | ||
| 1416 | 1628 | * |
| 1417 | 1629 | * @return {void} |
| 1418 | 1630 | */ |
| 1419 | 1631 | function fillMissingSignatureValidationFunction() { |
| 1420 | - if ( 'undefined' === typeof window.__FRMSIG || 'undefined' !== typeof window.frmFrontForm ) { | |
| 1632 | + if ( window.__FRMSIG === undefined || window.frmFrontForm !== undefined ) { | |
| 1421 | 1633 | return; |
| 1422 | 1634 | } |
| 1423 | 1635 | |
| 1424 | 1636 | window.frmFrontForm = { validateFormSubmit: () => {} }; |
| @@ -1457,9 +1669,9 @@ | ||
| 1457 | 1669 | } |
| 1458 | 1670 | |
| 1459 | 1671 | // Function to change the color of a select element |
| 1460 | 1672 | const changeSelectColor = select => { |
| 1461 | - 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' ) ) { | |
| 1462 | 1674 | select.style.setProperty( 'color', textColorDisabled, 'important' ); |
| 1463 | 1675 | } else { |
| 1464 | 1676 | select.style.color = ''; |
| 1465 | 1677 | } |