Add massive collection of CSS, JavaScript and theme assets that were previously excluded: **CSS Files (681 total):** - HVAC plugin-specific styles (hvac-*.css): 34 files including dashboard, certificates, registration, mobile nav, accessibility fixes, animations, and welcome popup - Theme framework files (Astra, builder systems, layouts): 200+ files - Plugin compatibility styles (WooCommerce, WPForms, Elementor, Contact Form 7): 150+ files - WordPress core and editor styles: 50+ files - Responsive and RTL language support: 200+ files **JavaScript Files (400+ total):** - HVAC plugin functionality (hvac-*.js): 27 files including menu systems, dashboard enhancements, profile sharing, mobile responsive features, accessibility, and animations - Framework and library files: jQuery plugins, GSAP, AOS, Swiper, Chart.js, Lottie, Isotope - Plugin compatibility scripts: WPForms, WooCommerce, Elementor, Contact Form 7, LifterLMS - WordPress core functionality: customizer, admin, block editor compatibility - Third-party integrations: Stripe, SMTP, analytics, search functionality **Assets:** - Certificate background images and logos - Comprehensive theme styling infrastructure - Mobile-responsive design systems - Cross-browser compatibility assets - Performance-optimized minified versions **Updated .gitignore:** - Fixed asset directory whitelisting patterns to properly include CSS/JS/images - Added proper directory structure recognition (!/assets/css/, !/assets/js/, etc.) - Maintains security by excluding sensitive files while including essential assets This commit provides the complete frontend infrastructure needed for: - Full theme functionality and styling - Plugin feature implementations - Mobile responsiveness and accessibility - Cross-browser compatibility - Performance optimization - Developer workflow support
2040 lines
56 KiB
JavaScript
2040 lines
56 KiB
JavaScript
/* global jconfirm, wpforms_gutenberg_form_selector, Choices, JSX, DOM, WPFormsUtils */
|
||
/* jshint es3: false, esversion: 6 */
|
||
|
||
/**
|
||
* @param strings.copy_paste_error
|
||
* @param strings.error_message
|
||
* @param strings.form_edit
|
||
* @param strings.form_entries
|
||
* @param strings.form_keywords
|
||
* @param strings.form_select
|
||
* @param strings.form_selected
|
||
* @param strings.form_settings
|
||
* @param strings.label_styles
|
||
* @param strings.other_styles
|
||
* @param strings.page_break
|
||
* @param strings.panel_notice_head
|
||
* @param strings.panel_notice_link
|
||
* @param strings.panel_notice_link_text
|
||
* @param strings.panel_notice_text
|
||
* @param strings.show_description
|
||
* @param strings.show_title
|
||
* @param strings.sublabel_hints
|
||
* @param strings.form_not_available_message
|
||
* @param urls.entries_url
|
||
* @param urls.form_url
|
||
* @param window.wpforms_choicesjs_config
|
||
* @param wpforms_education.upgrade_bonus
|
||
* @param wpforms_gutenberg_form_selector.block_empty_url
|
||
* @param wpforms_gutenberg_form_selector.block_preview_url
|
||
* @param wpforms_gutenberg_form_selector.get_started_url
|
||
* @param wpforms_gutenberg_form_selector.is_full_styling
|
||
* @param wpforms_gutenberg_form_selector.is_modern_markup
|
||
* @param wpforms_gutenberg_form_selector.logo_url
|
||
* @param wpforms_gutenberg_form_selector.wpforms_guide
|
||
*/
|
||
|
||
/**
|
||
* Gutenberg editor block.
|
||
*
|
||
* Common module.
|
||
*
|
||
* @since 1.8.8
|
||
*/
|
||
export default ( function( document, window, $ ) {
|
||
/**
|
||
* WP core components.
|
||
*
|
||
* @since 1.8.8
|
||
*/
|
||
const { serverSideRender: ServerSideRender = wp.components.ServerSideRender } = wp;
|
||
const { createElement, Fragment, createInterpolateElement } = wp.element;
|
||
const { registerBlockType } = wp.blocks;
|
||
const { InspectorControls, PanelColorSettings, useBlockProps } = wp.blockEditor || wp.editor;
|
||
const { SelectControl, ToggleControl, PanelBody, Placeholder } = wp.components;
|
||
const { __ } = wp.i18n;
|
||
const { useState, useEffect } = wp.element;
|
||
|
||
/**
|
||
* Localized data aliases.
|
||
*
|
||
* @since 1.8.8
|
||
*/
|
||
const { strings, defaults, sizes, urls, isPro, isLicenseActive, isAdmin } = wpforms_gutenberg_form_selector;
|
||
const defaultStyleSettings = defaults;
|
||
|
||
// noinspection JSUnusedLocalSymbols
|
||
/**
|
||
* WPForms Education script.
|
||
*
|
||
* @since 1.8.8
|
||
*/
|
||
const WPFormsEducation = window.WPFormsEducation || {}; // eslint-disable-line no-unused-vars
|
||
|
||
/**
|
||
* List of forms.
|
||
*
|
||
* The default value is localized in FormSelector.php.
|
||
*
|
||
* @since 1.8.4
|
||
*
|
||
* @type {Object}
|
||
*/
|
||
let formList = wpforms_gutenberg_form_selector.forms;
|
||
|
||
/**
|
||
* Blocks runtime data.
|
||
*
|
||
* @since 1.8.1
|
||
*
|
||
* @type {Object}
|
||
*/
|
||
const blocks = {};
|
||
|
||
/**
|
||
* Whether it is needed to trigger server rendering.
|
||
*
|
||
* @since 1.8.1
|
||
*
|
||
* @type {boolean}
|
||
*/
|
||
let triggerServerRender = true;
|
||
|
||
/**
|
||
* Popup container.
|
||
*
|
||
* @since 1.8.3
|
||
*
|
||
* @type {Object}
|
||
*/
|
||
let $popup = {};
|
||
|
||
/**
|
||
* Track fetch status.
|
||
*
|
||
* @since 1.8.4
|
||
*
|
||
* @type {boolean}
|
||
*/
|
||
let isFetching = false;
|
||
|
||
/**
|
||
* Elements holder.
|
||
*
|
||
* @since 1.8.8
|
||
*
|
||
* @type {Object}
|
||
*/
|
||
const el = {};
|
||
|
||
/**
|
||
* Common block attributes.
|
||
*
|
||
* @since 1.8.8
|
||
*
|
||
* @type {Object}
|
||
*/
|
||
let commonAttributes = {
|
||
clientId: {
|
||
type: 'string',
|
||
default: '',
|
||
},
|
||
formId: {
|
||
type: 'string',
|
||
default: defaultStyleSettings.formId,
|
||
},
|
||
displayTitle: {
|
||
type: 'boolean',
|
||
default: defaultStyleSettings.displayTitle,
|
||
},
|
||
displayDesc: {
|
||
type: 'boolean',
|
||
default: defaultStyleSettings.displayDesc,
|
||
},
|
||
preview: {
|
||
type: 'boolean',
|
||
},
|
||
theme: {
|
||
type: 'string',
|
||
default: defaultStyleSettings.theme,
|
||
},
|
||
themeName: {
|
||
type: 'string',
|
||
default: defaultStyleSettings.themeName,
|
||
},
|
||
labelSize: {
|
||
type: 'string',
|
||
default: defaultStyleSettings.labelSize,
|
||
},
|
||
labelColor: {
|
||
type: 'string',
|
||
default: defaultStyleSettings.labelColor,
|
||
},
|
||
labelSublabelColor: {
|
||
type: 'string',
|
||
default: defaultStyleSettings.labelSublabelColor,
|
||
},
|
||
labelErrorColor: {
|
||
type: 'string',
|
||
default: defaultStyleSettings.labelErrorColor,
|
||
},
|
||
pageBreakColor: {
|
||
type: 'string',
|
||
default: defaultStyleSettings.pageBreakColor,
|
||
},
|
||
customCss: {
|
||
type: 'string',
|
||
default: defaultStyleSettings.customCss,
|
||
},
|
||
copyPasteJsonValue: {
|
||
type: 'string',
|
||
default: defaultStyleSettings.copyPasteJsonValue,
|
||
},
|
||
};
|
||
|
||
/**
|
||
* Handlers for custom styles settings, defined outside this module.
|
||
*
|
||
* @since 1.8.8
|
||
*
|
||
* @type {Object}
|
||
*/
|
||
let customStylesHandlers = {};
|
||
|
||
/**
|
||
* Dropdown timeout.
|
||
*
|
||
* @since 1.8.8
|
||
*
|
||
* @type {number}
|
||
*/
|
||
let dropdownTimeout;
|
||
|
||
/**
|
||
* Whether copy-paste content was generated on edit.
|
||
*
|
||
* @since 1.9.1
|
||
*
|
||
* @type {boolean}
|
||
*/
|
||
let isCopyPasteGeneratedOnEdit = false;
|
||
|
||
/**
|
||
* Whether the background is selected.
|
||
*
|
||
* @since 1.9.3
|
||
*
|
||
* @type {boolean}
|
||
*/
|
||
let backgroundSelected = false;
|
||
|
||
/**
|
||
* Public functions and properties.
|
||
*
|
||
* @since 1.8.1
|
||
*
|
||
* @type {Object}
|
||
*/
|
||
const app = {
|
||
|
||
/**
|
||
* Panel modules.
|
||
*
|
||
* @since 1.8.8
|
||
*
|
||
* @type {Object}
|
||
*/
|
||
panels: {},
|
||
|
||
/**
|
||
* Start the engine.
|
||
*
|
||
* @since 1.8.1
|
||
*
|
||
* @param {Object} blockOptions Block options.
|
||
*/
|
||
init( blockOptions ) {
|
||
el.$window = $( window );
|
||
app.panels = blockOptions.panels;
|
||
app.education = blockOptions.education;
|
||
|
||
app.initDefaults( blockOptions );
|
||
app.registerBlock( blockOptions );
|
||
|
||
app.initJConfirm();
|
||
|
||
$( app.ready );
|
||
},
|
||
|
||
/**
|
||
* Document ready.
|
||
*
|
||
* @since 1.8.1
|
||
*/
|
||
ready() {
|
||
app.events();
|
||
},
|
||
|
||
/**
|
||
* Events.
|
||
*
|
||
* @since 1.8.1
|
||
*/
|
||
events() {
|
||
el.$window
|
||
.on( 'wpformsFormSelectorEdit', _.debounce( app.blockEdit, 250 ) )
|
||
.on( 'wpformsFormSelectorFormLoaded', app.formLoaded );
|
||
},
|
||
|
||
/**
|
||
* Init jConfirm.
|
||
*
|
||
* @since 1.8.8
|
||
*/
|
||
initJConfirm() {
|
||
// jquery-confirm defaults.
|
||
jconfirm.defaults = {
|
||
closeIcon: false,
|
||
backgroundDismiss: false,
|
||
escapeKey: true,
|
||
animationBounce: 1,
|
||
useBootstrap: false,
|
||
theme: 'modern',
|
||
boxWidth: '400px',
|
||
animateFromElement: false,
|
||
};
|
||
},
|
||
|
||
/**
|
||
* Get a fresh list of forms via REST-API.
|
||
*
|
||
* @since 1.8.4
|
||
*
|
||
* @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-api-fetch/
|
||
*/
|
||
async getForms() {
|
||
// If a fetch is already in progress, exit the function.
|
||
if ( isFetching ) {
|
||
return;
|
||
}
|
||
|
||
// Set the flag to true indicating a fetch is in progress.
|
||
isFetching = true;
|
||
|
||
try {
|
||
// Fetch forms.
|
||
formList = await wp.apiFetch( {
|
||
path: wpforms_gutenberg_form_selector.route_namespace + 'forms/',
|
||
method: 'GET',
|
||
cache: 'no-cache',
|
||
} );
|
||
} catch ( error ) {
|
||
// eslint-disable-next-line no-console
|
||
console.error( error );
|
||
} finally {
|
||
isFetching = false;
|
||
}
|
||
},
|
||
|
||
/**
|
||
* Open builder popup.
|
||
*
|
||
* @since 1.6.2
|
||
*
|
||
* @param {string} clientID Block Client ID.
|
||
*/
|
||
openBuilderPopup( clientID ) {
|
||
if ( $.isEmptyObject( $popup ) ) {
|
||
const parent = $( '#wpwrap' );
|
||
const canvasIframe = $( 'iframe[name="editor-canvas"]' );
|
||
const isFseMode = Boolean( canvasIframe.length );
|
||
const tmpl = isFseMode ? canvasIframe.contents().find( '#wpforms-gutenberg-popup' ) : $( '#wpforms-gutenberg-popup' );
|
||
|
||
parent.after( tmpl );
|
||
|
||
$popup = parent.siblings( '#wpforms-gutenberg-popup' );
|
||
}
|
||
|
||
const url = wpforms_gutenberg_form_selector.get_started_url,
|
||
$iframe = $popup.find( 'iframe' );
|
||
|
||
app.builderCloseButtonEvent( clientID );
|
||
$iframe.attr( 'src', url );
|
||
$popup.fadeIn();
|
||
},
|
||
|
||
/**
|
||
* Close button (inside the form builder) click event.
|
||
*
|
||
* @since 1.8.3
|
||
*
|
||
* @param {string} clientID Block Client ID.
|
||
*/
|
||
builderCloseButtonEvent( clientID ) {
|
||
$popup
|
||
.off( 'wpformsBuilderInPopupClose' )
|
||
.on( 'wpformsBuilderInPopupClose', function( e, action, formId, formTitle ) {
|
||
if ( action !== 'saved' || ! formId ) {
|
||
return;
|
||
}
|
||
|
||
// Insert a new block when a new form is created from the popup to update the form list and attributes.
|
||
const newBlock = wp.blocks.createBlock( 'wpforms/form-selector', {
|
||
formId: formId.toString(), // Expects string value, make sure we insert string.
|
||
} );
|
||
|
||
// eslint-disable-next-line camelcase
|
||
formList = [ { ID: formId, post_title: formTitle } ];
|
||
|
||
// Insert a new block.
|
||
wp.data.dispatch( 'core/block-editor' ).removeBlock( clientID );
|
||
wp.data.dispatch( 'core/block-editor' ).insertBlocks( newBlock );
|
||
} );
|
||
},
|
||
|
||
/**
|
||
* Register block.
|
||
*
|
||
* @since 1.8.1
|
||
*
|
||
* @param {Object} blockOptions Additional block options.
|
||
*/
|
||
// eslint-disable-next-line max-lines-per-function
|
||
registerBlock( blockOptions ) {
|
||
registerBlockType( 'wpforms/form-selector', {
|
||
title: strings.title,
|
||
description: strings.description,
|
||
icon: app.getIcon(),
|
||
keywords: strings.form_keywords,
|
||
category: 'widgets',
|
||
attributes: app.getBlockAttributes(),
|
||
supports: {
|
||
customClassName: app.hasForms(),
|
||
},
|
||
example: {
|
||
attributes: {
|
||
preview: true,
|
||
},
|
||
},
|
||
// eslint-disable-next-line max-lines-per-function,complexity
|
||
edit( props ) {
|
||
const { attributes } = props;
|
||
const formOptions = app.getFormOptions();
|
||
const handlers = app.getSettingsFieldsHandlers( props );
|
||
|
||
const [ isNotDisabled ] = useState( isPro && isLicenseActive ); // eslint-disable-line react-hooks/rules-of-hooks
|
||
const [ isProEnabled ] = useState( isPro ); // eslint-disable-line react-hooks/rules-of-hooks, no-unused-vars
|
||
const [ showBackgroundPreview, setShowBackgroundPreview ] = useState( blockOptions.panels.background._showBackgroundPreview( props ) ); // eslint-disable-line react-hooks/rules-of-hooks
|
||
const [ lastBgImage, setLastBgImage ] = useState( '' ); // eslint-disable-line react-hooks/rules-of-hooks
|
||
|
||
const uiState = {
|
||
isNotDisabled,
|
||
isProEnabled,
|
||
showBackgroundPreview,
|
||
setShowBackgroundPreview,
|
||
lastBgImage,
|
||
setLastBgImage,
|
||
};
|
||
|
||
useEffect( () => { // eslint-disable-line react-hooks/rules-of-hooks
|
||
if ( attributes.formId ) {
|
||
setShowBackgroundPreview(
|
||
props.attributes.backgroundImage !== 'none' &&
|
||
props.attributes.backgroundUrl &&
|
||
props.attributes.backgroundUrl !== 'url()'
|
||
);
|
||
}
|
||
}, [ backgroundSelected, props.attributes.backgroundImage, props.attributes.backgroundUrl ] ); // eslint-disable-line react-hooks/exhaustive-deps
|
||
|
||
// Get block properties.
|
||
const blockProps = useBlockProps(); // eslint-disable-line react-hooks/rules-of-hooks, no-unused-vars
|
||
|
||
// Store block clientId in attributes.
|
||
if ( ! attributes.clientId || ! app.isClientIdAttrUnique( props ) ) {
|
||
// We just want the client ID to update once.
|
||
// The block editor doesn't have a fixed block ID, so we need to get it on the initial load, but only once.
|
||
props.setAttributes( { clientId: props.clientId } );
|
||
}
|
||
|
||
// Main block settings.
|
||
const jsx = [
|
||
app.jsxParts.getMainSettings( attributes, handlers, formOptions ),
|
||
];
|
||
|
||
// Block preview picture.
|
||
if ( ! app.hasForms() ) {
|
||
jsx.push(
|
||
app.jsxParts.getEmptyFormsPreview( props ),
|
||
);
|
||
|
||
return <div { ...blockProps }>{ jsx }</div>;
|
||
}
|
||
|
||
const sizeOptions = app.getSizeOptions();
|
||
|
||
// Show placeholder when form is not available (trashed, deleted etc.).
|
||
if ( attributes && attributes.formId && app.isFormAvailable( attributes.formId ) === false ) {
|
||
// Block placeholder (form selector).
|
||
jsx.push(
|
||
app.jsxParts.getBlockPlaceholder( props.attributes, handlers, formOptions ),
|
||
);
|
||
|
||
return <div { ...blockProps }>{ jsx }</div>;
|
||
}
|
||
|
||
// Form style settings & block content.
|
||
if ( attributes.formId ) {
|
||
// Subscribe to block events.
|
||
app.maybeSubscribeToBlockEvents( props, handlers, blockOptions );
|
||
|
||
jsx.push(
|
||
app.jsxParts.getStyleSettings( props, handlers, sizeOptions, blockOptions, uiState ),
|
||
app.jsxParts.getBlockFormContent( props )
|
||
);
|
||
|
||
if ( ! isCopyPasteGeneratedOnEdit ) {
|
||
handlers.updateCopyPasteContent();
|
||
|
||
isCopyPasteGeneratedOnEdit = true;
|
||
}
|
||
|
||
el.$window.trigger( 'wpformsFormSelectorEdit', [ props ] );
|
||
|
||
return <div { ...blockProps }>{ jsx }</div>;
|
||
}
|
||
|
||
// Block preview picture.
|
||
if ( attributes.preview ) {
|
||
jsx.push(
|
||
app.jsxParts.getBlockPreview(),
|
||
);
|
||
|
||
return <div { ...blockProps }>{ jsx }</div>;
|
||
}
|
||
|
||
// Block placeholder (form selector).
|
||
jsx.push(
|
||
app.jsxParts.getBlockPlaceholder( props.attributes, handlers, formOptions ),
|
||
);
|
||
|
||
return <div { ...blockProps }>{ jsx }</div>;
|
||
},
|
||
save: () => null,
|
||
} );
|
||
},
|
||
|
||
/**
|
||
* Init default style settings.
|
||
*
|
||
* @since 1.8.1
|
||
* @since 1.8.8 Added blockOptions parameter.
|
||
*
|
||
* @param {Object} blockOptions Additional block options.
|
||
*/
|
||
initDefaults( blockOptions = {} ) {
|
||
commonAttributes = {
|
||
...commonAttributes,
|
||
...blockOptions.getCommonAttributes(),
|
||
};
|
||
customStylesHandlers = blockOptions.setStylesHandlers;
|
||
|
||
[ 'formId', 'copyPasteJsonValue' ].forEach( ( key ) => delete defaultStyleSettings[ key ] );
|
||
},
|
||
|
||
/**
|
||
* Check if the site has forms.
|
||
*
|
||
* @since 1.8.3
|
||
*
|
||
* @return {boolean} Whether site has at least one form.
|
||
*/
|
||
hasForms() {
|
||
return formList.length > 0;
|
||
},
|
||
|
||
/**
|
||
* Check if form is available to be previewed.
|
||
*
|
||
* @since 1.8.9
|
||
*
|
||
* @param {number} formId Form ID.
|
||
*
|
||
* @return {boolean} Whether form is available.
|
||
*/
|
||
isFormAvailable( formId ) {
|
||
return formList.find( ( { ID } ) => ID === Number( formId ) ) !== undefined;
|
||
},
|
||
|
||
/**
|
||
* Set triggerServerRender flag.
|
||
*
|
||
* @since 1.8.8
|
||
*
|
||
* @param {boolean} $flag The value of the triggerServerRender flag.
|
||
*/
|
||
setTriggerServerRender( $flag ) {
|
||
triggerServerRender = Boolean( $flag );
|
||
},
|
||
|
||
/**
|
||
* Maybe subscribe to block events.
|
||
*
|
||
* @since 1.8.8
|
||
*
|
||
* @param {Object} subscriberProps Subscriber block properties.
|
||
* @param {Object} subscriberHandlers Subscriber block event handlers.
|
||
* @param {Object} subscriberBlockOptions Subscriber block options.
|
||
*/
|
||
maybeSubscribeToBlockEvents( subscriberProps, subscriberHandlers, subscriberBlockOptions ) {
|
||
const id = subscriberProps.clientId;
|
||
|
||
// Unsubscribe from block events.
|
||
// This is needed to avoid multiple subscriptions when the block is re-rendered.
|
||
el.$window
|
||
.off( 'wpformsFormSelectorDeleteTheme.' + id )
|
||
.off( 'wpformsFormSelectorUpdateTheme.' + id )
|
||
.off( 'wpformsFormSelectorSetTheme.' + id );
|
||
|
||
// Subscribe to block events.
|
||
el.$window
|
||
.on( 'wpformsFormSelectorDeleteTheme.' + id, app.subscriberDeleteTheme( subscriberProps, subscriberBlockOptions ) )
|
||
.on( 'wpformsFormSelectorUpdateTheme.' + id, app.subscriberUpdateTheme( subscriberProps, subscriberBlockOptions ) )
|
||
.on( 'wpformsFormSelectorSetTheme.' + id, app.subscriberSetTheme( subscriberProps, subscriberBlockOptions ) );
|
||
},
|
||
|
||
/**
|
||
* Block event `wpformsFormSelectorDeleteTheme` handler.
|
||
*
|
||
* @since 1.8.8
|
||
*
|
||
* @param {Object} subscriberProps Subscriber block properties
|
||
* @param {Object} subscriberBlockOptions Subscriber block options.
|
||
*
|
||
* @return {Function} Event handler.
|
||
*/
|
||
subscriberDeleteTheme( subscriberProps, subscriberBlockOptions ) {
|
||
return function( e, themeSlug, triggerProps ) {
|
||
if ( subscriberProps.clientId === triggerProps.clientId ) {
|
||
return;
|
||
}
|
||
|
||
if ( subscriberProps?.attributes?.theme !== themeSlug ) {
|
||
return;
|
||
}
|
||
|
||
if ( ! subscriberBlockOptions?.panels?.themes ) {
|
||
return;
|
||
}
|
||
|
||
// Reset theme to default one.
|
||
subscriberBlockOptions.panels.themes.setBlockTheme( subscriberProps, 'default' );
|
||
};
|
||
},
|
||
|
||
/**
|
||
* Block event `wpformsFormSelectorDeleteTheme` handler.
|
||
*
|
||
* @since 1.8.8
|
||
*
|
||
* @param {Object} subscriberProps Subscriber block properties
|
||
* @param {Object} subscriberBlockOptions Subscriber block options.
|
||
*
|
||
* @return {Function} Event handler.
|
||
*/
|
||
subscriberUpdateTheme( subscriberProps, subscriberBlockOptions ) {
|
||
return function( e, themeSlug, themeData, triggerProps ) {
|
||
if ( subscriberProps.clientId === triggerProps.clientId ) {
|
||
return;
|
||
}
|
||
|
||
if ( subscriberProps?.attributes?.theme !== themeSlug ) {
|
||
return;
|
||
}
|
||
|
||
if ( ! subscriberBlockOptions?.panels?.themes ) {
|
||
return;
|
||
}
|
||
|
||
// Reset theme to default one.
|
||
subscriberBlockOptions.panels.themes.setBlockTheme( subscriberProps, themeSlug );
|
||
};
|
||
},
|
||
|
||
/**
|
||
* Block event `wpformsFormSelectorSetTheme` handler.
|
||
*
|
||
* @since 1.8.8
|
||
*
|
||
* @param {Object} subscriberProps Subscriber block properties
|
||
* @param {Object} subscriberBlockOptions Subscriber block options.
|
||
*
|
||
* @return {Function} Event handler.
|
||
*/
|
||
subscriberSetTheme( subscriberProps, subscriberBlockOptions ) {
|
||
// noinspection JSUnusedLocalSymbols
|
||
return function( e, block, themeSlug, triggerProps ) { // eslint-disable-line no-unused-vars
|
||
if ( subscriberProps.clientId === triggerProps.clientId ) {
|
||
return;
|
||
}
|
||
|
||
if ( ! subscriberBlockOptions?.panels?.themes ) {
|
||
return;
|
||
}
|
||
|
||
// Set theme.
|
||
app.onSetTheme( subscriberProps );
|
||
};
|
||
},
|
||
|
||
/**
|
||
* Block JSX parts.
|
||
*
|
||
* @since 1.8.1
|
||
*
|
||
* @type {Object}
|
||
*/
|
||
jsxParts: {
|
||
|
||
/**
|
||
* Get main settings JSX code.
|
||
*
|
||
* @since 1.8.1
|
||
*
|
||
* @param {Object} attributes Block attributes.
|
||
* @param {Object} handlers Block event handlers.
|
||
* @param {Object} formOptions Form selector options.
|
||
*
|
||
* @return {JSX.Element} Main setting JSX code.
|
||
*/
|
||
getMainSettings( attributes, handlers, formOptions ) {
|
||
if ( ! app.hasForms() ) {
|
||
return app.jsxParts.printEmptyFormsNotice( attributes.clientId );
|
||
}
|
||
|
||
return (
|
||
<InspectorControls key="wpforms-gutenberg-form-selector-inspector-main-settings">
|
||
<PanelBody className="wpforms-gutenberg-panel wpforms-gutenberg-panel-form-settings" title={ strings.form_settings }>
|
||
<SelectControl
|
||
label={ strings.form_selected }
|
||
value={ attributes.formId }
|
||
options={ formOptions }
|
||
onChange={ ( value ) => handlers.attrChange( 'formId', value ) }
|
||
/>
|
||
{ attributes.formId ? (
|
||
<>
|
||
<p className="wpforms-gutenberg-form-selector-actions">
|
||
<a href={ urls.form_url.replace( '{ID}', attributes.formId ) } rel="noreferrer" target="_blank">
|
||
{ strings.form_edit }
|
||
</a>
|
||
{ isPro && isLicenseActive && (
|
||
<>
|
||
|
|
||
<a
|
||
href={ urls.entries_url.replace( '{ID}', attributes.formId ) }
|
||
rel="noreferrer"
|
||
target="_blank"
|
||
>{ strings.form_entries }</a>
|
||
</>
|
||
) }
|
||
</p>
|
||
<ToggleControl
|
||
label={ strings.show_title }
|
||
checked={ attributes.displayTitle }
|
||
onChange={ ( value ) => handlers.attrChange( 'displayTitle', value ) }
|
||
/>
|
||
<ToggleControl
|
||
label={ strings.show_description }
|
||
checked={ attributes.displayDesc }
|
||
onChange={ ( value ) => handlers.attrChange( 'displayDesc', value ) }
|
||
/>
|
||
</>
|
||
) : null }
|
||
<p className="wpforms-gutenberg-panel-notice">
|
||
<strong>{ strings.panel_notice_head }</strong>
|
||
{ strings.panel_notice_text }
|
||
<a href={ strings.panel_notice_link } rel="noreferrer" target="_blank">{ strings.panel_notice_link_text }</a>
|
||
</p>
|
||
</PanelBody>
|
||
</InspectorControls>
|
||
);
|
||
},
|
||
|
||
/**
|
||
* Print empty forms notice.
|
||
*
|
||
* @since 1.8.3
|
||
*
|
||
* @param {string} clientId Block client ID.
|
||
*
|
||
* @return {JSX.Element} Field styles JSX code.
|
||
*/
|
||
printEmptyFormsNotice( clientId ) {
|
||
return (
|
||
<InspectorControls key="wpforms-gutenberg-form-selector-inspector-main-settings">
|
||
<PanelBody className="wpforms-gutenberg-panel" title={ strings.form_settings }>
|
||
<p className="wpforms-gutenberg-panel-notice wpforms-warning wpforms-empty-form-notice" style={ { display: 'block' } }>
|
||
<strong>{ __( 'You haven’t created a form, yet!', 'wpforms-lite' ) }</strong>
|
||
{ __( 'What are you waiting for?', 'wpforms-lite' ) }
|
||
</p>
|
||
<button type="button" className="get-started-button components-button is-secondary"
|
||
onClick={
|
||
() => {
|
||
app.openBuilderPopup( clientId );
|
||
}
|
||
}
|
||
>
|
||
{ __( 'Get Started', 'wpforms-lite' ) }
|
||
</button>
|
||
</PanelBody>
|
||
</InspectorControls>
|
||
);
|
||
},
|
||
|
||
/**
|
||
* Get Label styles JSX code.
|
||
*
|
||
* @since 1.8.1
|
||
*
|
||
* @param {Object} props Block properties.
|
||
* @param {Object} handlers Block event handlers.
|
||
* @param {Object} sizeOptions Size selector options.
|
||
*
|
||
* @return {Object} Label styles JSX code.
|
||
*/
|
||
getLabelStyles( props, handlers, sizeOptions ) {
|
||
return (
|
||
<PanelBody className={ app.getPanelClass( props ) } title={ strings.label_styles }>
|
||
<SelectControl
|
||
label={ strings.size }
|
||
value={ props.attributes.labelSize }
|
||
className="wpforms-gutenberg-form-selector-fix-bottom-margin"
|
||
options={ sizeOptions }
|
||
onChange={ ( value ) => handlers.styleAttrChange( 'labelSize', value ) }
|
||
/>
|
||
|
||
<div className="wpforms-gutenberg-form-selector-color-picker">
|
||
<div className="wpforms-gutenberg-form-selector-control-label">{ strings.colors }</div>
|
||
<PanelColorSettings
|
||
__experimentalIsRenderedInSidebar
|
||
enableAlpha
|
||
showTitle={ false }
|
||
className="wpforms-gutenberg-form-selector-color-panel"
|
||
colorSettings={ [
|
||
{
|
||
value: props.attributes.labelColor,
|
||
onChange: ( value ) => handlers.styleAttrChange( 'labelColor', value ),
|
||
label: strings.label,
|
||
},
|
||
{
|
||
value: props.attributes.labelSublabelColor,
|
||
onChange: ( value ) => handlers.styleAttrChange( 'labelSublabelColor', value ),
|
||
label: strings.sublabel_hints.replace( '&', '&' ),
|
||
},
|
||
{
|
||
value: props.attributes.labelErrorColor,
|
||
onChange: ( value ) => handlers.styleAttrChange( 'labelErrorColor', value ),
|
||
label: strings.error_message,
|
||
},
|
||
] }
|
||
/>
|
||
</div>
|
||
</PanelBody>
|
||
);
|
||
},
|
||
|
||
/**
|
||
* Get Page Indicator styles JSX code.
|
||
*
|
||
* @since 1.8.7
|
||
*
|
||
* @param {Object} props Block properties.
|
||
* @param {Object} handlers Block event handlers.
|
||
*
|
||
* @return {Object} Page Indicator styles JSX code.
|
||
*/
|
||
getPageIndicatorStyles( props, handlers ) { // eslint-disable-line complexity
|
||
const hasPageBreak = app.hasPageBreak( formList, props.attributes.formId );
|
||
const hasRating = app.hasRating( formList, props.attributes.formId );
|
||
|
||
if ( ! hasPageBreak && ! hasRating ) {
|
||
return null;
|
||
}
|
||
|
||
let label = '';
|
||
if ( hasPageBreak && hasRating ) {
|
||
label = `${ strings.page_break } / ${ strings.rating }`;
|
||
} else if ( hasPageBreak ) {
|
||
label = strings.page_break;
|
||
} else if ( hasRating ) {
|
||
label = strings.rating;
|
||
}
|
||
|
||
return (
|
||
<PanelBody className={ app.getPanelClass( props ) } title={ strings.other_styles }>
|
||
<div className="wpforms-gutenberg-form-selector-color-picker">
|
||
<div className="wpforms-gutenberg-form-selector-control-label">{ strings.colors }</div>
|
||
<PanelColorSettings
|
||
__experimentalIsRenderedInSidebar
|
||
enableAlpha
|
||
showTitle={ false }
|
||
className="wpforms-gutenberg-form-selector-color-panel"
|
||
colorSettings={ [
|
||
{
|
||
value: props.attributes.pageBreakColor,
|
||
onChange: ( value ) => handlers.styleAttrChange( 'pageBreakColor', value ),
|
||
label,
|
||
},
|
||
] } />
|
||
</div>
|
||
</PanelBody>
|
||
);
|
||
},
|
||
|
||
/**
|
||
* Get style settings JSX code.
|
||
*
|
||
* @since 1.8.1
|
||
*
|
||
* @param {Object} props Block properties.
|
||
* @param {Object} handlers Block event handlers.
|
||
* @param {Object} sizeOptions Size selector options.
|
||
* @param {Object} blockOptions Block options loaded from external modules.
|
||
*
|
||
* @param {Object} uiState UI state.
|
||
*
|
||
* @return {Object} Inspector controls JSX code.
|
||
*/
|
||
getStyleSettings( props, handlers, sizeOptions, blockOptions, uiState ) {
|
||
return (
|
||
<InspectorControls key="wpforms-gutenberg-form-selector-style-settings">
|
||
{ blockOptions.getThemesPanel( props, app, blockOptions.stockPhotos ) }
|
||
{ blockOptions.getFieldStyles( props, handlers, sizeOptions, app ) }
|
||
{ app.jsxParts.getLabelStyles( props, handlers, sizeOptions ) }
|
||
{ blockOptions.getButtonStyles( props, handlers, sizeOptions, app ) }
|
||
{ blockOptions.getContainerStyles( props, handlers, app, uiState ) }
|
||
{ blockOptions.getBackgroundStyles( props, handlers, app, blockOptions.stockPhotos, uiState ) }
|
||
{ app.jsxParts.getPageIndicatorStyles( props, handlers ) }
|
||
</InspectorControls>
|
||
);
|
||
},
|
||
|
||
/**
|
||
* Get block content JSX code.
|
||
*
|
||
* @since 1.8.1
|
||
*
|
||
* @param {Object} props Block properties.
|
||
*
|
||
* @return {JSX.Element} Block content JSX code.
|
||
*/
|
||
getBlockFormContent( props ) {
|
||
if ( triggerServerRender ) {
|
||
return (
|
||
<ServerSideRender
|
||
key="wpforms-gutenberg-form-selector-server-side-renderer"
|
||
block="wpforms/form-selector"
|
||
attributes={ props.attributes }
|
||
/>
|
||
);
|
||
}
|
||
|
||
const clientId = props.clientId;
|
||
const block = app.getBlockContainer( props );
|
||
|
||
// In the case of empty content, use server side renderer.
|
||
// This happens when the block is duplicated or converted to a reusable block.
|
||
if ( ! block?.innerHTML ) {
|
||
triggerServerRender = true;
|
||
|
||
return app.jsxParts.getBlockFormContent( props );
|
||
}
|
||
|
||
blocks[ clientId ] = blocks[ clientId ] || {};
|
||
blocks[ clientId ].blockHTML = block.innerHTML;
|
||
blocks[ clientId ].loadedFormId = props.attributes.formId;
|
||
|
||
return (
|
||
<Fragment key="wpforms-gutenberg-form-selector-fragment-form-html">
|
||
<div dangerouslySetInnerHTML={ { __html: blocks[ clientId ].blockHTML } } />
|
||
</Fragment>
|
||
);
|
||
},
|
||
|
||
/**
|
||
* Get block preview JSX code.
|
||
*
|
||
* @since 1.8.1
|
||
*
|
||
* @return {JSX.Element} Block preview JSX code.
|
||
*/
|
||
getBlockPreview() {
|
||
return (
|
||
<Fragment
|
||
key="wpforms-gutenberg-form-selector-fragment-block-preview">
|
||
<img src={ wpforms_gutenberg_form_selector.block_preview_url } style={ { width: '100%' } } alt="" />
|
||
</Fragment>
|
||
);
|
||
},
|
||
|
||
/**
|
||
* Get block empty JSX code.
|
||
*
|
||
* @since 1.8.3
|
||
*
|
||
* @param {Object} props Block properties.
|
||
* @return {JSX.Element} Block empty JSX code.
|
||
*/
|
||
getEmptyFormsPreview( props ) {
|
||
const clientId = props.clientId;
|
||
|
||
return (
|
||
<Fragment
|
||
key="wpforms-gutenberg-form-selector-fragment-block-empty">
|
||
<div className="wpforms-no-form-preview">
|
||
<img src={ wpforms_gutenberg_form_selector.block_empty_url } alt="" />
|
||
<p>
|
||
{
|
||
createInterpolateElement(
|
||
__(
|
||
'You can use <b>WPForms</b> to build contact forms, surveys, payment forms, and more with just a few clicks.',
|
||
'wpforms-lite'
|
||
),
|
||
{
|
||
b: <strong />,
|
||
}
|
||
)
|
||
}
|
||
</p>
|
||
<button type="button" className="get-started-button components-button is-primary"
|
||
onClick={
|
||
() => {
|
||
app.openBuilderPopup( clientId );
|
||
}
|
||
}
|
||
>
|
||
{ __( 'Get Started', 'wpforms-lite' ) }
|
||
</button>
|
||
<p className="empty-desc">
|
||
{
|
||
createInterpolateElement(
|
||
__(
|
||
'Need some help? Check out our <a>comprehensive guide.</a>',
|
||
'wpforms-lite'
|
||
),
|
||
{
|
||
// eslint-disable-next-line jsx-a11y/anchor-has-content
|
||
a: <a href={ wpforms_gutenberg_form_selector.wpforms_guide } target="_blank" rel="noopener noreferrer" />,
|
||
}
|
||
)
|
||
}
|
||
</p>
|
||
|
||
{ /* Template for popup with builder iframe */ }
|
||
<div id="wpforms-gutenberg-popup" className="wpforms-builder-popup">
|
||
<iframe src="about:blank" width="100%" height="100%" id="wpforms-builder-iframe" title="WPForms Builder Popup"></iframe>
|
||
</div>
|
||
</div>
|
||
</Fragment>
|
||
);
|
||
},
|
||
|
||
/**
|
||
* Get block placeholder (form selector) JSX code.
|
||
*
|
||
* @since 1.8.1
|
||
*
|
||
* @param {Object} attributes Block attributes.
|
||
* @param {Object} handlers Block event handlers.
|
||
* @param {Object} formOptions Form selector options.
|
||
*
|
||
* @return {JSX.Element} Block placeholder JSX code.
|
||
*/
|
||
getBlockPlaceholder( attributes, handlers, formOptions ) {
|
||
const isFormNotAvailable = attributes.formId && ! app.isFormAvailable( attributes.formId );
|
||
|
||
return (
|
||
<Placeholder
|
||
key="wpforms-gutenberg-form-selector-wrap"
|
||
className="wpforms-gutenberg-form-selector-wrap">
|
||
<img src={ wpforms_gutenberg_form_selector.logo_url } alt="" />
|
||
{ isFormNotAvailable && (
|
||
<p style={ { textAlign: 'center', marginTop: '0' } }>
|
||
{ strings.form_not_available_message }
|
||
</p>
|
||
) }
|
||
<SelectControl
|
||
key="wpforms-gutenberg-form-selector-select-control"
|
||
value={ attributes.formId }
|
||
options={ formOptions }
|
||
onChange={ ( value ) => handlers.attrChange( 'formId', value ) }
|
||
/>
|
||
</Placeholder>
|
||
);
|
||
},
|
||
},
|
||
|
||
/**
|
||
* Determine if the form has a Page Break field.
|
||
*
|
||
* @since 1.8.7
|
||
*
|
||
* @param {Object} forms The forms' data object.
|
||
* @param {number|string} formId Form ID.
|
||
*
|
||
* @return {boolean} True when the form has a Page Break field, false otherwise.
|
||
*/
|
||
hasPageBreak( forms, formId ) {
|
||
const currentForm = forms.find( ( form ) => parseInt( form.ID, 10 ) === parseInt( formId, 10 ) );
|
||
|
||
if ( ! currentForm.post_content ) {
|
||
return false;
|
||
}
|
||
|
||
const fields = JSON.parse( currentForm.post_content )?.fields;
|
||
|
||
return Object.values( fields ).some( ( field ) => field.type === 'pagebreak' );
|
||
},
|
||
|
||
hasRating( forms, formId ) {
|
||
const currentForm = forms.find( ( form ) => parseInt( form.ID, 10 ) === parseInt( formId, 10 ) );
|
||
|
||
if ( ! currentForm.post_content || ! isPro || ! isLicenseActive ) {
|
||
return false;
|
||
}
|
||
|
||
const fields = JSON.parse( currentForm.post_content )?.fields;
|
||
|
||
return Object.values( fields ).some( ( field ) => field.type === 'rating' );
|
||
},
|
||
|
||
/**
|
||
* Get Style Settings panel class.
|
||
*
|
||
* @since 1.8.1
|
||
*
|
||
* @param {Object} props Block properties.
|
||
* @param {string} panel Panel name.
|
||
*
|
||
* @return {string} Style Settings panel class.
|
||
*/
|
||
getPanelClass( props, panel = '' ) {
|
||
let cssClass = 'wpforms-gutenberg-panel wpforms-block-settings-' + props.clientId;
|
||
|
||
if ( ! app.isFullStylingEnabled() ) {
|
||
cssClass += ' disabled_panel';
|
||
}
|
||
|
||
// Restrict styling panel for non-admins.
|
||
if ( ! ( isAdmin || panel === 'themes' ) ) {
|
||
cssClass += ' wpforms-gutenberg-panel-restricted';
|
||
}
|
||
|
||
return cssClass;
|
||
},
|
||
|
||
/**
|
||
* Get color panel settings CSS class.
|
||
*
|
||
* @since 1.8.8
|
||
*
|
||
* @param {string} borderStyle Border style value.
|
||
*
|
||
* @return {string} Style Settings panel class.
|
||
*/
|
||
getColorPanelClass( borderStyle ) {
|
||
let cssClass = 'wpforms-gutenberg-form-selector-color-panel';
|
||
|
||
if ( borderStyle === 'none' ) {
|
||
cssClass += ' wpforms-gutenberg-form-selector-border-color-disabled';
|
||
}
|
||
|
||
return cssClass;
|
||
},
|
||
|
||
/**
|
||
* Determine whether the full styling is enabled.
|
||
*
|
||
* @since 1.8.1
|
||
*
|
||
* @return {boolean} Whether the full styling is enabled.
|
||
*/
|
||
isFullStylingEnabled() {
|
||
return wpforms_gutenberg_form_selector.is_modern_markup && wpforms_gutenberg_form_selector.is_full_styling;
|
||
},
|
||
|
||
/**
|
||
* Determine whether the block has lead forms enabled.
|
||
*
|
||
* @since 1.9.0
|
||
*
|
||
* @param {Object} block Gutenberg block
|
||
*
|
||
* @return {boolean} Whether the block has lead forms enabled
|
||
*/
|
||
isLeadFormsEnabled( block ) {
|
||
if ( ! block ) {
|
||
return false;
|
||
}
|
||
|
||
const $form = $( block.querySelector( '.wpforms-container' ) );
|
||
|
||
return $form.hasClass( 'wpforms-lead-forms-container' );
|
||
},
|
||
|
||
/**
|
||
* Get block container DOM element.
|
||
*
|
||
* @since 1.8.1
|
||
*
|
||
* @param {Object} props Block properties.
|
||
*
|
||
* @return {Element} Block container.
|
||
*/
|
||
getBlockContainer( props ) {
|
||
const blockSelector = `#block-${ props.clientId } > div`;
|
||
let block = document.querySelector( blockSelector );
|
||
|
||
// For FSE / Gutenberg plugin, we need to take a look inside the iframe.
|
||
if ( ! block ) {
|
||
const editorCanvas = document.querySelector( 'iframe[name="editor-canvas"]' );
|
||
|
||
block = editorCanvas?.contentWindow.document.querySelector( blockSelector );
|
||
}
|
||
|
||
return block;
|
||
},
|
||
|
||
/**
|
||
* Get form container in Block Editor.
|
||
*
|
||
* @since 1.9.3
|
||
*
|
||
* @param {number} formId Form ID.
|
||
*
|
||
* @return {Element|null} Form container.
|
||
*/
|
||
getFormBlock( formId ) {
|
||
// First, try to find the iframe for blocks version 3.
|
||
const editorCanvas = document.querySelector( 'iframe[name="editor-canvas"]' );
|
||
|
||
// If the iframe is found, try to find the form.
|
||
return editorCanvas?.contentWindow.document.querySelector( `#wpforms-${ formId }` ) || $( `#wpforms-${ formId }` );
|
||
},
|
||
|
||
/**
|
||
* Update CSS variable(s) value(s) of the given attribute for given container on the preview.
|
||
*
|
||
* @since 1.8.8
|
||
*
|
||
* @param {string} attribute Style attribute: field-size, label-size, button-size, etc.
|
||
* @param {string} value Property new value.
|
||
* @param {Element} container Form container.
|
||
* @param {Object} props Block properties.
|
||
*/
|
||
updatePreviewCSSVarValue( attribute, value, container, props ) { // eslint-disable-line complexity, max-lines-per-function
|
||
if ( ! container || ! attribute ) {
|
||
return;
|
||
}
|
||
|
||
const property = attribute.replace(
|
||
/[A-Z]/g,
|
||
( letter ) => `-${ letter.toLowerCase() }`
|
||
);
|
||
|
||
if ( typeof customStylesHandlers[ property ] === 'function' ) {
|
||
customStylesHandlers[ property ]( container, value );
|
||
|
||
return;
|
||
}
|
||
|
||
switch ( property ) {
|
||
case 'field-size':
|
||
case 'label-size':
|
||
case 'button-size':
|
||
case 'container-shadow-size':
|
||
for ( const key in sizes[ property ][ value ] ) {
|
||
container.style.setProperty(
|
||
`--wpforms-${ property }-${ key }`,
|
||
sizes[ property ][ value ][ key ],
|
||
);
|
||
}
|
||
|
||
break;
|
||
case 'field-border-style':
|
||
if ( value === 'none' ) {
|
||
app.toggleFieldBorderNoneCSSVarValue( container, true );
|
||
} else {
|
||
app.toggleFieldBorderNoneCSSVarValue( container, false );
|
||
container.style.setProperty( `--wpforms-${ property }`, value );
|
||
}
|
||
|
||
break;
|
||
case 'button-background-color':
|
||
app.maybeUpdateAccentColor( props.attributes.buttonBorderColor, value, container );
|
||
value = app.maybeSetButtonAltBackgroundColor( value, props.attributes.buttonBorderColor, container );
|
||
app.maybeSetButtonAltTextColor( props.attributes.buttonTextColor, value, props.attributes.buttonBorderColor, container );
|
||
container.style.setProperty( `--wpforms-${ property }`, value );
|
||
|
||
break;
|
||
case 'button-border-color':
|
||
app.maybeUpdateAccentColor( value, props.attributes.buttonBackgroundColor, container );
|
||
app.maybeSetButtonAltTextColor( props.attributes.buttonTextColor, props.attributes.buttonBackgroundColor, value, container );
|
||
container.style.setProperty( `--wpforms-${ property }`, value );
|
||
|
||
break;
|
||
case 'button-text-color':
|
||
app.maybeSetButtonAltTextColor( value, props.attributes.buttonBackgroundColor, props.attributes.buttonBorderColor, container );
|
||
container.style.setProperty( `--wpforms-${ property }`, value );
|
||
|
||
break;
|
||
default:
|
||
container.style.setProperty( `--wpforms-${ property }`, value );
|
||
container.style.setProperty( `--wpforms-${ property }-spare`, value );
|
||
}
|
||
},
|
||
|
||
/**
|
||
* Set/unset field border vars in case of border-style is none.
|
||
*
|
||
* @since 1.8.8
|
||
*
|
||
* @param {Object} container Form container.
|
||
* @param {boolean} set True when set, false when unset.
|
||
*/
|
||
toggleFieldBorderNoneCSSVarValue( container, set ) {
|
||
const cont = container.querySelector( 'form' );
|
||
|
||
if ( set ) {
|
||
cont.style.setProperty( '--wpforms-field-border-style', 'solid' );
|
||
cont.style.setProperty( '--wpforms-field-border-size', '1px' );
|
||
cont.style.setProperty( '--wpforms-field-border-color', 'transparent' );
|
||
|
||
return;
|
||
}
|
||
|
||
cont.style.setProperty( '--wpforms-field-border-style', null );
|
||
cont.style.setProperty( '--wpforms-field-border-size', null );
|
||
cont.style.setProperty( '--wpforms-field-border-color', null );
|
||
},
|
||
|
||
/**
|
||
* Maybe set the button's alternative background color.
|
||
*
|
||
* @since 1.8.8
|
||
*
|
||
* @param {string} value Attribute value.
|
||
* @param {string} buttonBorderColor Button border color.
|
||
* @param {Object} container Form container.
|
||
*
|
||
* @return {string|*} New background color.
|
||
*/
|
||
maybeSetButtonAltBackgroundColor( value, buttonBorderColor, container ) {
|
||
// Setting css property value to child `form` element overrides the parent property value.
|
||
const form = container.querySelector( 'form' );
|
||
|
||
form.style.setProperty( '--wpforms-button-background-color-alt', value );
|
||
|
||
if ( WPFormsUtils.cssColorsUtils.isTransparentColor( value ) ) {
|
||
return WPFormsUtils.cssColorsUtils.isTransparentColor( buttonBorderColor ) ? defaultStyleSettings.buttonBackgroundColor : buttonBorderColor;
|
||
}
|
||
|
||
return value;
|
||
},
|
||
|
||
/**
|
||
* Maybe set the button's alternative text color.
|
||
*
|
||
* @since 1.8.8
|
||
*
|
||
* @param {string} value Attribute value.
|
||
* @param {string} buttonBackgroundColor Button background color.
|
||
* @param {string} buttonBorderColor Button border color.
|
||
* @param {Object} container Form container.
|
||
*/
|
||
maybeSetButtonAltTextColor( value, buttonBackgroundColor, buttonBorderColor, container ) {
|
||
const form = container.querySelector( 'form' );
|
||
|
||
let altColor = null;
|
||
|
||
value = value.toLowerCase();
|
||
|
||
if (
|
||
WPFormsUtils.cssColorsUtils.isTransparentColor( value ) ||
|
||
value === buttonBackgroundColor ||
|
||
(
|
||
WPFormsUtils.cssColorsUtils.isTransparentColor( buttonBackgroundColor ) &&
|
||
value === buttonBorderColor
|
||
)
|
||
) {
|
||
altColor = WPFormsUtils.cssColorsUtils.getContrastColor( buttonBackgroundColor );
|
||
}
|
||
|
||
container.style.setProperty( `--wpforms-button-text-color-alt`, value );
|
||
form.style.setProperty( `--wpforms-button-text-color-alt`, altColor );
|
||
},
|
||
|
||
/**
|
||
* Maybe update accent color.
|
||
*
|
||
* @since 1.8.8
|
||
*
|
||
* @param {string} color Color value.
|
||
* @param {string} buttonBackgroundColor Button background color.
|
||
* @param {Object} container Form container.
|
||
*/
|
||
maybeUpdateAccentColor( color, buttonBackgroundColor, container ) {
|
||
// Setting css property value to child `form` element overrides the parent property value.
|
||
const form = container.querySelector( 'form' );
|
||
|
||
// Fallback to default color if the border color is transparent.
|
||
color = WPFormsUtils.cssColorsUtils.isTransparentColor( color ) ? defaultStyleSettings.buttonBackgroundColor : color;
|
||
|
||
if ( WPFormsUtils.cssColorsUtils.isTransparentColor( buttonBackgroundColor ) ) {
|
||
form.style.setProperty( '--wpforms-button-background-color-alt', 'rgba( 0, 0, 0, 0 )' );
|
||
form.style.setProperty( '--wpforms-button-background-color', color );
|
||
} else {
|
||
container.style.setProperty( '--wpforms-button-background-color-alt', buttonBackgroundColor );
|
||
form.style.setProperty( '--wpforms-button-background-color-alt', null );
|
||
form.style.setProperty( '--wpforms-button-background-color', null );
|
||
}
|
||
},
|
||
|
||
/**
|
||
* Get settings fields event handlers.
|
||
*
|
||
* @since 1.8.1
|
||
*
|
||
* @param {Object} props Block properties.
|
||
*
|
||
* @return {Object} Object that contains event handlers for the settings fields.
|
||
*/
|
||
getSettingsFieldsHandlers( props ) { // eslint-disable-line max-lines-per-function
|
||
return {
|
||
/**
|
||
* Field style attribute change event handler.
|
||
*
|
||
* @since 1.8.1
|
||
*
|
||
* @param {string} attribute Attribute name.
|
||
* @param {string} value New attribute value.
|
||
*/
|
||
styleAttrChange( attribute, value ) {
|
||
const block = app.getBlockContainer( props ),
|
||
container = block.querySelector( `#wpforms-${ props.attributes.formId }` ),
|
||
setAttr = {};
|
||
|
||
// Unset the color means setting the transparent color.
|
||
if ( attribute.includes( 'Color' ) ) {
|
||
value = value ?? 'rgba( 0, 0, 0, 0 )';
|
||
}
|
||
|
||
app.updatePreviewCSSVarValue( attribute, value, container, props );
|
||
|
||
setAttr[ attribute ] = value;
|
||
|
||
app.setBlockRuntimeStateVar( props.clientId, 'prevAttributesState', props.attributes );
|
||
props.setAttributes( setAttr );
|
||
|
||
triggerServerRender = false;
|
||
|
||
this.updateCopyPasteContent();
|
||
|
||
app.panels.themes.updateCustomThemeAttribute( attribute, value, props );
|
||
|
||
this.maybeToggleDropdown( props, attribute );
|
||
|
||
// Trigger event for developers.
|
||
el.$window.trigger( 'wpformsFormSelectorStyleAttrChange', [ block, props, attribute, value ] );
|
||
},
|
||
|
||
/**
|
||
* Handles the toggling of the dropdown menu's visibility.
|
||
*
|
||
* @since 1.8.8
|
||
*
|
||
* @param {Object} props The block properties.
|
||
* @param {string} attribute The name of the attribute being changed.
|
||
*/
|
||
maybeToggleDropdown( props, attribute ) { // eslint-disable-line no-shadow
|
||
const formId = props.attributes.formId;
|
||
const menu = document.querySelector( `#wpforms-form-${ formId } .choices__list.choices__list--dropdown` );
|
||
const classicMenu = document.querySelector( `#wpforms-form-${ formId } .wpforms-field-select-style-classic select` );
|
||
|
||
if ( attribute === 'fieldMenuColor' ) {
|
||
if ( menu ) {
|
||
menu.classList.add( 'is-active' );
|
||
menu.parentElement.classList.add( 'is-open' );
|
||
} else {
|
||
this.showClassicMenu( classicMenu );
|
||
}
|
||
|
||
clearTimeout( dropdownTimeout );
|
||
|
||
dropdownTimeout = setTimeout( () => {
|
||
const toClose = document.querySelector( `#wpforms-form-${ formId } .choices__list.choices__list--dropdown` );
|
||
|
||
if ( toClose ) {
|
||
toClose.classList.remove( 'is-active' );
|
||
toClose.parentElement.classList.remove( 'is-open' );
|
||
} else {
|
||
this.hideClassicMenu( document.querySelector( `#wpforms-form-${ formId } .wpforms-field-select-style-classic select` ) );
|
||
}
|
||
}, 5000 );
|
||
} else if ( menu ) {
|
||
menu.classList.remove( 'is-active' );
|
||
} else {
|
||
this.hideClassicMenu( classicMenu );
|
||
}
|
||
},
|
||
|
||
/**
|
||
* Shows the classic menu.
|
||
*
|
||
* @since 1.8.8
|
||
*
|
||
* @param {Object} classicMenu The classic menu.
|
||
*/
|
||
showClassicMenu( classicMenu ) {
|
||
if ( ! classicMenu ) {
|
||
return;
|
||
}
|
||
|
||
classicMenu.size = 2;
|
||
classicMenu.style.cssText = 'padding-top: 40px; padding-inline-end: 0; padding-inline-start: 0; position: relative;';
|
||
classicMenu.querySelectorAll( 'option' ).forEach( ( option ) => {
|
||
option.style.cssText = 'border-left: 1px solid #8c8f94; border-right: 1px solid #8c8f94; padding: 0 10px; z-index: 999999; position: relative;';
|
||
} );
|
||
classicMenu.querySelector( 'option:last-child' ).style.cssText = 'border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; padding: 0 10px; border-left: 1px solid #8c8f94; border-right: 1px solid #8c8f94; border-bottom: 1px solid #8c8f94; z-index: 999999; position: relative;';
|
||
},
|
||
|
||
/**
|
||
* Hides the classic menu.
|
||
*
|
||
* @since 1.8.8
|
||
*
|
||
* @param {Object} classicMenu The classic menu.
|
||
*/
|
||
hideClassicMenu( classicMenu ) {
|
||
if ( ! classicMenu ) {
|
||
return;
|
||
}
|
||
|
||
classicMenu.size = 0;
|
||
classicMenu.style.cssText = 'padding-top: 0; padding-inline-end: 24px; padding-inline-start: 12px; position: relative;';
|
||
classicMenu.querySelectorAll( 'option' ).forEach( ( option ) => {
|
||
option.style.cssText = 'border: none;';
|
||
} );
|
||
},
|
||
|
||
/**
|
||
* Field regular attribute change event handler.
|
||
*
|
||
* @since 1.8.1
|
||
*
|
||
* @param {string} attribute Attribute name.
|
||
* @param {string} value New attribute value.
|
||
*/
|
||
attrChange( attribute, value ) {
|
||
const setAttr = {};
|
||
|
||
setAttr[ attribute ] = value;
|
||
|
||
app.setBlockRuntimeStateVar( props.clientId, 'prevAttributesState', props.attributes );
|
||
props.setAttributes( setAttr );
|
||
|
||
triggerServerRender = true;
|
||
|
||
this.updateCopyPasteContent();
|
||
},
|
||
|
||
/**
|
||
* Update content of the "Copy/Paste" fields.
|
||
*
|
||
* @since 1.8.1
|
||
*/
|
||
updateCopyPasteContent() {
|
||
const content = {};
|
||
const atts = wp.data.select( 'core/block-editor' ).getBlockAttributes( props.clientId );
|
||
|
||
for ( const key in defaultStyleSettings ) {
|
||
content[ key ] = atts[ key ];
|
||
}
|
||
|
||
props.setAttributes( { copyPasteJsonValue: JSON.stringify( content ) } );
|
||
},
|
||
|
||
/**
|
||
* Paste settings handler.
|
||
*
|
||
* @since 1.8.1
|
||
*
|
||
* @param {string} value New attribute value.
|
||
*/
|
||
pasteSettings( value ) {
|
||
value = value.trim();
|
||
|
||
const pasteAttributes = app.parseValidateJson( value );
|
||
|
||
if ( ! pasteAttributes ) {
|
||
if ( value ) {
|
||
wp.data.dispatch( 'core/notices' ).createErrorNotice(
|
||
strings.copy_paste_error,
|
||
{ id: 'wpforms-json-parse-error' }
|
||
);
|
||
}
|
||
|
||
this.updateCopyPasteContent();
|
||
|
||
return;
|
||
}
|
||
|
||
pasteAttributes.copyPasteJsonValue = value;
|
||
|
||
const themeSlug = app.panels.themes.maybeCreateCustomThemeFromAttributes( pasteAttributes );
|
||
|
||
app.setBlockRuntimeStateVar( props.clientId, 'prevAttributesState', props.attributes );
|
||
props.setAttributes( pasteAttributes );
|
||
app.panels.themes.setBlockTheme( props, themeSlug );
|
||
|
||
triggerServerRender = false;
|
||
},
|
||
};
|
||
},
|
||
|
||
/**
|
||
* Parse and validate JSON string.
|
||
*
|
||
* @since 1.8.1
|
||
*
|
||
* @param {string} value JSON string.
|
||
*
|
||
* @return {boolean|object} Parsed JSON object OR false on error.
|
||
*/
|
||
parseValidateJson( value ) {
|
||
if ( typeof value !== 'string' ) {
|
||
return false;
|
||
}
|
||
|
||
let atts;
|
||
|
||
try {
|
||
atts = JSON.parse( value.trim() );
|
||
} catch ( error ) {
|
||
atts = false;
|
||
}
|
||
|
||
return atts;
|
||
},
|
||
|
||
/**
|
||
* Get WPForms icon DOM element.
|
||
*
|
||
* @since 1.8.1
|
||
*
|
||
* @return {DOM.element} WPForms icon DOM element.
|
||
*/
|
||
getIcon() {
|
||
return createElement(
|
||
'svg',
|
||
{ width: 20, height: 20, viewBox: '0 0 612 612', className: 'dashicon' },
|
||
createElement(
|
||
'path',
|
||
{
|
||
fill: 'currentColor',
|
||
d: 'M544,0H68C30.445,0,0,30.445,0,68v476c0,37.556,30.445,68,68,68h476c37.556,0,68-30.444,68-68V68 C612,30.445,581.556,0,544,0z M464.44,68L387.6,120.02L323.34,68H464.44z M288.66,68l-64.26,52.02L147.56,68H288.66z M544,544H68 V68h22.1l136,92.14l79.9-64.6l79.56,64.6l136-92.14H544V544z M114.24,263.16h95.88v-48.28h-95.88V263.16z M114.24,360.4h95.88 v-48.62h-95.88V360.4z M242.76,360.4h255v-48.62h-255V360.4L242.76,360.4z M242.76,263.16h255v-48.28h-255V263.16L242.76,263.16z M368.22,457.3h129.54V408H368.22V457.3z',
|
||
},
|
||
),
|
||
);
|
||
},
|
||
|
||
/**
|
||
* Get WPForms blocks.
|
||
*
|
||
* @since 1.8.8
|
||
*
|
||
* @return {Array} Blocks array.
|
||
*/
|
||
getWPFormsBlocks() {
|
||
const wpformsBlocks = wp.data.select( 'core/block-editor' ).getBlocks();
|
||
|
||
return wpformsBlocks.filter( ( props ) => {
|
||
return props.name === 'wpforms/form-selector';
|
||
} );
|
||
},
|
||
|
||
/**
|
||
* Get WPForms blocks.
|
||
*
|
||
* @since 1.8.8
|
||
*
|
||
* @param {Object} props Block properties.
|
||
*
|
||
* @return {Object} Block attributes.
|
||
*/
|
||
isClientIdAttrUnique( props ) {
|
||
const wpformsBlocks = app.getWPFormsBlocks();
|
||
|
||
for ( const key in wpformsBlocks ) {
|
||
// Skip the current block.
|
||
if ( wpformsBlocks[ key ].clientId === props.clientId ) {
|
||
continue;
|
||
}
|
||
|
||
if ( wpformsBlocks[ key ].attributes.clientId === props.attributes.clientId ) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
},
|
||
|
||
/**
|
||
* Get block attributes.
|
||
*
|
||
* @since 1.8.1
|
||
*
|
||
* @return {Object} Block attributes.
|
||
*/
|
||
getBlockAttributes() {
|
||
return commonAttributes;
|
||
},
|
||
|
||
/**
|
||
* Get block runtime state variable.
|
||
*
|
||
* @since 1.8.8
|
||
*
|
||
* @param {string} clientId Block client ID.
|
||
* @param {string} varName Block runtime variable name.
|
||
*
|
||
* @return {*} Block runtime state variable value.
|
||
*/
|
||
getBlockRuntimeStateVar( clientId, varName ) {
|
||
return blocks[ clientId ]?.[ varName ];
|
||
},
|
||
|
||
/**
|
||
* Set block runtime state variable value.
|
||
*
|
||
* @since 1.8.8
|
||
*
|
||
* @param {string} clientId Block client ID.
|
||
* @param {string} varName Block runtime state key.
|
||
* @param {*} value State variable value.
|
||
*
|
||
* @return {boolean} True on success.
|
||
*/
|
||
setBlockRuntimeStateVar( clientId, varName, value ) { // eslint-disable-line complexity
|
||
if ( ! clientId || ! varName ) {
|
||
return false;
|
||
}
|
||
|
||
blocks[ clientId ] = blocks[ clientId ] || {};
|
||
blocks[ clientId ][ varName ] = value;
|
||
|
||
// Prevent referencing to object.
|
||
if ( typeof value === 'object' && ! Array.isArray( value ) && value !== null ) {
|
||
blocks[ clientId ][ varName ] = { ...value };
|
||
}
|
||
|
||
return true;
|
||
},
|
||
|
||
/**
|
||
* Get form selector options.
|
||
*
|
||
* @since 1.8.1
|
||
*
|
||
* @return {Array} Form options.
|
||
*/
|
||
getFormOptions() {
|
||
const formOptions = formList.map( ( value ) => (
|
||
{ value: value.ID, label: value.post_title }
|
||
) );
|
||
|
||
formOptions.unshift( { value: '', label: strings.form_select } );
|
||
|
||
return formOptions;
|
||
},
|
||
|
||
/**
|
||
* Get size selector options.
|
||
*
|
||
* @since 1.8.1
|
||
*
|
||
* @return {Array} Size options.
|
||
*/
|
||
getSizeOptions() {
|
||
return [
|
||
{
|
||
label: strings.small,
|
||
value: 'small',
|
||
},
|
||
{
|
||
label: strings.medium,
|
||
value: 'medium',
|
||
},
|
||
{
|
||
label: strings.large,
|
||
value: 'large',
|
||
},
|
||
];
|
||
},
|
||
|
||
/**
|
||
* Event `wpformsFormSelectorEdit` handler.
|
||
*
|
||
* @since 1.8.1
|
||
*
|
||
* @param {Object} e Event object.
|
||
* @param {Object} props Block properties.
|
||
*/
|
||
blockEdit( e, props ) {
|
||
const block = app.getBlockContainer( props );
|
||
|
||
if ( ! block?.dataset ) {
|
||
return;
|
||
}
|
||
|
||
app.initLeadFormSettings( block.parentElement );
|
||
},
|
||
|
||
/**
|
||
* Init Lead Form Settings panels.
|
||
*
|
||
* @since 1.8.1
|
||
*
|
||
* @param {Element} block Block element.
|
||
* @param {Object} block.dataset Block element.
|
||
*/
|
||
initLeadFormSettings( block ) {
|
||
if ( ! block?.dataset ) {
|
||
return;
|
||
}
|
||
|
||
if ( ! app.isFullStylingEnabled() ) {
|
||
return;
|
||
}
|
||
|
||
const clientId = block.dataset.block;
|
||
const $panel = $( `.wpforms-block-settings-${ clientId }` );
|
||
|
||
if ( app.isLeadFormsEnabled( block ) ) {
|
||
$panel
|
||
.addClass( 'disabled_panel' )
|
||
.find( '.wpforms-gutenberg-panel-notice.wpforms-lead-form-notice' )
|
||
.css( 'display', 'block' );
|
||
|
||
$panel
|
||
.find( '.wpforms-gutenberg-panel-notice.wpforms-use-modern-notice' )
|
||
.css( 'display', 'none' );
|
||
|
||
return;
|
||
}
|
||
|
||
$panel
|
||
.removeClass( 'disabled_panel' )
|
||
.find( '.wpforms-gutenberg-panel-notice.wpforms-lead-form-notice' )
|
||
.css( 'display', 'none' );
|
||
|
||
$panel
|
||
.find( '.wpforms-gutenberg-panel-notice.wpforms-use-modern-notice' )
|
||
.css( 'display', null );
|
||
},
|
||
|
||
/**
|
||
* Event `wpformsFormSelectorFormLoaded` handler.
|
||
*
|
||
* @since 1.8.1
|
||
*
|
||
* @param {Object} e Event object.
|
||
*/
|
||
formLoaded( e ) {
|
||
app.initLeadFormSettings( e.detail.block );
|
||
app.updateAccentColors( e.detail );
|
||
app.loadChoicesJS( e.detail );
|
||
app.initRichTextField( e.detail.formId );
|
||
app.initRepeaterField( e.detail.formId );
|
||
|
||
$( e.detail.block )
|
||
.off( 'click' )
|
||
.on( 'click', app.blockClick );
|
||
},
|
||
|
||
/**
|
||
* Click on the block event handler.
|
||
*
|
||
* @since 1.8.1
|
||
*
|
||
* @param {Object} e Event object.
|
||
*/
|
||
blockClick( e ) {
|
||
app.initLeadFormSettings( e.currentTarget );
|
||
},
|
||
|
||
/**
|
||
* Update accent colors of some fields in GB block in Modern Markup mode.
|
||
*
|
||
* @since 1.8.1
|
||
*
|
||
* @param {Object} detail Event details object.
|
||
*/
|
||
updateAccentColors( detail ) {
|
||
if (
|
||
! wpforms_gutenberg_form_selector.is_modern_markup ||
|
||
! window.WPForms?.FrontendModern ||
|
||
! detail?.block
|
||
) {
|
||
return;
|
||
}
|
||
|
||
const $form = $( detail.block.querySelector( `#wpforms-${ detail.formId }` ) ),
|
||
FrontendModern = window.WPForms.FrontendModern;
|
||
|
||
FrontendModern.updateGBBlockPageIndicatorColor( $form );
|
||
FrontendModern.updateGBBlockIconChoicesColor( $form );
|
||
FrontendModern.updateGBBlockRatingColor( $form );
|
||
},
|
||
|
||
/**
|
||
* Init Modern style Dropdown fields (<select>).
|
||
*
|
||
* @since 1.8.1
|
||
*
|
||
* @param {Object} detail Event details object.
|
||
*/
|
||
loadChoicesJS( detail ) {
|
||
if ( typeof window.Choices !== 'function' ) {
|
||
return;
|
||
}
|
||
|
||
const $form = $( detail.block.querySelector( `#wpforms-${ detail.formId }` ) );
|
||
|
||
$form.find( '.choicesjs-select' ).each( function( idx, selectEl ) {
|
||
const $el = $( selectEl );
|
||
|
||
if ( $el.data( 'choice' ) === 'active' ) {
|
||
return;
|
||
}
|
||
|
||
const args = window.wpforms_choicesjs_config || {},
|
||
searchEnabled = $el.data( 'search-enabled' ),
|
||
$field = $el.closest( '.wpforms-field' );
|
||
|
||
args.searchEnabled = 'undefined' !== typeof searchEnabled ? searchEnabled : true;
|
||
args.callbackOnInit = function() {
|
||
const self = this,
|
||
$element = $( self.passedElement.element ),
|
||
$input = $( self.input.element ),
|
||
sizeClass = $element.data( 'size-class' );
|
||
|
||
// Add CSS-class for size.
|
||
if ( sizeClass ) {
|
||
$( self.containerOuter.element ).addClass( sizeClass );
|
||
}
|
||
|
||
/**
|
||
* If a multiple select has selected choices - hide a placeholder text.
|
||
* In case if select is empty - we return placeholder text.
|
||
*/
|
||
if ( $element.prop( 'multiple' ) ) {
|
||
// On init event.
|
||
$input.data( 'placeholder', $input.attr( 'placeholder' ) );
|
||
|
||
if ( self.getValue( true ).length ) {
|
||
$input.hide();
|
||
}
|
||
}
|
||
|
||
this.disable();
|
||
$field.find( '.is-disabled' ).removeClass( 'is-disabled' );
|
||
};
|
||
|
||
try {
|
||
if ( ! ( selectEl instanceof parent.HTMLSelectElement ) ) {
|
||
Object.setPrototypeOf( selectEl, parent.HTMLSelectElement.prototype );
|
||
}
|
||
|
||
$el.data( 'choicesjs', new parent.Choices( selectEl, args ) );
|
||
} catch ( e ) {} // eslint-disable-line no-empty
|
||
} );
|
||
},
|
||
|
||
/**
|
||
* Initialize RichText field.
|
||
*
|
||
* @since 1.8.1
|
||
*
|
||
* @param {number} formId Form ID.
|
||
*/
|
||
initRichTextField( formId ) {
|
||
const form = app.getFormBlock( formId );
|
||
|
||
if ( ! form ) {
|
||
return;
|
||
}
|
||
|
||
// Set default tab to `Visual`.
|
||
$( form ).find( '.wp-editor-wrap' ).removeClass( 'html-active' ).addClass( 'tmce-active' );
|
||
},
|
||
|
||
/**
|
||
* Initialize Repeater field.
|
||
*
|
||
* @since 1.8.9
|
||
*
|
||
* @param {number} formId Form ID.
|
||
*/
|
||
initRepeaterField( formId ) {
|
||
const form = app.getFormBlock( formId );
|
||
|
||
if ( ! form ) {
|
||
return;
|
||
}
|
||
|
||
const $rowButtons = $( form ).find( '.wpforms-field-repeater > .wpforms-field-repeater-display-rows .wpforms-field-repeater-display-rows-buttons' );
|
||
|
||
// Get the label height and set the button position.
|
||
$rowButtons.each( function() {
|
||
const $cont = $( this );
|
||
const $labels = $cont.siblings( '.wpforms-layout-column' )
|
||
.find( '.wpforms-field' )
|
||
.find( '.wpforms-field-label' );
|
||
|
||
if ( ! $labels.length ) {
|
||
return;
|
||
}
|
||
|
||
const $label = $labels.first();
|
||
const labelStyle = window.getComputedStyle( $label.get( 0 ) );
|
||
const margin = labelStyle?.getPropertyValue( '--wpforms-field-size-input-spacing' ) || 0;
|
||
const height = $label.outerHeight() || 0;
|
||
const top = height + parseInt( margin, 10 ) + 10;
|
||
|
||
$cont.css( { top } );
|
||
} );
|
||
|
||
// Init buttons and descriptions for each repeater in each form.
|
||
$( `.wpforms-form[data-formid="${ formId }"]` ).each( function() {
|
||
const $repeater = $( this ).find( '.wpforms-field-repeater' );
|
||
|
||
$repeater.find( '.wpforms-field-repeater-display-rows-buttons' ).addClass( 'wpforms-init' );
|
||
$repeater.find( '.wpforms-field-repeater-display-rows:last .wpforms-field-description' ).addClass( 'wpforms-init' );
|
||
} );
|
||
},
|
||
|
||
/**
|
||
* Handle theme change.
|
||
*
|
||
* @since 1.9.3
|
||
*
|
||
* @param {Object} props Block properties.
|
||
*/
|
||
onSetTheme( props ) {
|
||
backgroundSelected = props.attributes.backgroundImage !== 'url()';
|
||
},
|
||
};
|
||
|
||
// Provide access to public functions/properties.
|
||
return app;
|
||
}( document, window, jQuery ) );
|