<?php

// phpcs:ignore Generic.Commenting.DocComment.MissingShort
/** @noinspection AutoloadingIssuesInspection */

use WPForms\Forms\Fields\Traits\MultiFieldMenu as MultiFieldMenuTrait;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Fields management panel.
 *
 * @since 1.0.0
 */
class WPForms_Builder_Panel_Fields extends WPForms_Builder_Panel {

	use MultiFieldMenuTrait;

	/**
	 * All systems go.
	 *
	 * @since 1.0.0
	 *
	 * @noinspection ReturnTypeCanBeDeclaredInspection
	 */
	public function init() {

		// Define panel information.
		$this->name    = esc_html__( 'Fields', 'wpforms-lite' );
		$this->slug    = 'fields';
		$this->icon    = 'fa-list-alt';
		$this->order   = 10;
		$this->sidebar = true;

		$this->hooks();
	}

	/**
	 * Add hooks.
	 *
	 * @since 1.9.8
	 *
	 * @return void
	 */
	private function hooks(): void {

		if ( ! $this->form ) {
			return;
		}

		add_action( 'wpforms_builder_fields', [ $this, 'search' ], 5 );
		add_action( 'wpforms_builder_fields', [ $this, 'fields' ] );
		add_action( 'wpforms_builder_fields_options', [ $this, 'fields_options' ] );
		add_action( 'wpforms_builder_preview', [ $this, 'preview' ] );
		add_filter( 'wpforms_builder_strings', [ $this, 'multi_select_strings' ] );

		// Template for form builder previews.
		add_action( 'wpforms_builder_print_footer_scripts', [ $this, 'field_preview_templates' ] );
		add_action( 'wpforms_builder_print_footer_scripts', [ $this, 'choices_limit_message_template' ] );
		add_action( 'wpforms_builder_print_footer_scripts', [ $this, 'choices_empty_message_template' ] );
	}

	/**
	 * Enqueue assets for the Fields panel.
	 *
	 * @since 1.0.0
	 * @since 1.6.8 All the builder stylesheets enqueues moved to the `\WPForms_Builder::enqueues()`.
	 *
	 * @noinspection ReturnTypeCanBeDeclaredInspection
	 */
	public function enqueues() {

		$min = wpforms_get_min_suffix();

		wp_enqueue_script(
			'wpforms-builder-drag-fields',
			WPFORMS_PLUGIN_URL . "assets/js/admin/builder/drag-fields{$min}.js",
			[ 'wpforms-builder' ],
			WPFORMS_VERSION,
			true
		);

		wp_enqueue_script(
			'wpforms-builder-search-fields',
			WPFORMS_PLUGIN_URL . "assets/js/admin/builder/search-fields{$min}.js",
			[ 'wpforms-builder' ],
			WPFORMS_VERSION,
			true
		);
	}

	/**
	 * Add Multi-Select Builder strings.
	 *
	 * @since 1.9.9
	 *
	 * @param array $strings Form Builder strings.
	 *
	 * @return array Form Builder strings.
	 */
	public function multi_select_strings( array $strings ): array {

		$strings['multi_select'] = [
			'repeater_tooltip'    => esc_html__( "The Repeater field can't be selected with other fields.", 'wpforms-lite' ),
			'layout_tooltip'      => esc_html__( "The Layout field can't be selected with other fields.", 'wpforms-lite' ),
			'general_tooltip'     => esc_html__( 'This field can’t be selected alongside Layout or Repeater fields.', 'wpforms-lite' ),
			/* translators: %s - Cmd or Ctrl key. */
			'copy_toast_single'   => esc_html__( 'Field copied. Use %1$s + V to paste.', 'wpforms-lite' ),
			/* translators: %d - number of fields, %s - Cmd or Ctrl key. */
			'copy_toast_multiple' => esc_html__( '%1$d fields copied. Use %2$s + V to paste.', 'wpforms-lite' ),
		];

		return $strings;
	}

	/**
	 * Output the Field panel sidebar.
	 *
	 * @since 1.0.0
	 *
	 * @noinspection ReturnTypeCanBeDeclaredInspection
	 */
	public function panel_sidebar() {

		// Sidebar contents are not valid unless we have a form.
		if ( ! $this->form ) {
			return;
		}
		?>
		<ul class="wpforms-tabs wpforms-clear">

			<li class="wpforms-tab" id="add-fields">
				<a href="#" class="active">
					<i class="fa fa-list-alt"></i><?php esc_html_e( 'Add Fields', 'wpforms-lite' ); ?>
				</a>
			</li>

			<li class="wpforms-tab" id="field-options">
				<a href="#">
					<i class="fa fa-sliders"></i><?php esc_html_e( 'Field Options', 'wpforms-lite' ); ?>
				</a>
			</li>

		</ul>

		<div id="wpforms-add-fields-tab" class="wpforms-add-fields wpforms-tab-content">
			<?php
			/**
			 * Fires to add fields.
			 *
			 * @since 1.0.0
			 *
			 * @param array $form Form.
			 */
			do_action( 'wpforms_builder_fields', $this->form ); // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
			?>
		</div>

		<div id="wpforms-field-options" class="wpforms-field-options wpforms-tab-content">
			<?php
			/**
			 * Fires to add field options.
			 *
			 * @since 1.0.0
			 *
			 * @param array $form Form.
			 */
			do_action( 'wpforms_builder_fields_options', $this->form ); // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
			?>
		</div>
		<?php
	}

	/**
	 * Output the Field panel primary content.
	 *
	 * @since 1.0.0
	 *
	 * @noinspection ReturnTypeCanBeDeclaredInspection
	 */
	public function panel_content() {

		// Check if there is a form created.
		if ( ! $this->form ) {
			echo '<div class="wpforms-alert wpforms-alert-info">';
			echo wp_kses(
				__( 'You need to <a href="#" class="wpforms-panel-switch" data-panel="setup">set up your form</a> before you can manage the fields.', 'wpforms-lite' ),
				[
					'a' => [
						'href'       => [],
						'class'      => [],
						'data-panel' => [],
					],
				]
			);
			echo '</div>';

			return;
		}

		?>

		<div class="wpforms-preview-wrap">

			<div class="wpforms-preview">

				<div class="wpforms-title-desc">
					<div class="wpforms-title-desc-inner">
						<h2 class="wpforms-form-name">
							<?php echo esc_html( $this->form_data['settings']['form_title'] ?? $this->form->post_title ); ?>
						</h2>
						<span class="wpforms-form-desc">
							<?php
							echo wp_kses(
								$this->form_data['settings']['form_desc'] ?? $this->form->post_excerpt,
								wpforms_builder_preview_get_allowed_tags()
							);
							?>
						</span>
					</div>
				</div>

				<?php

				/**
				 * Fires after the fields panel (form preview) title.
				 *
				 * @since 1.9.4
				 *
				 * @param array $form_data Form data.
				 */
				do_action( 'wpforms_builder_panel_fields_panel_content_title_after', $this->form_data );
				?>

				<div class="wpforms-no-fields-holder wpforms-hidden">
					<?php $this->no_fields_options(); ?>
					<?php $this->no_fields_preview(); ?>
				</div>

				<div class="wpforms-field-wrap">
					<?php
					/**
					 * Fires to output the form preview.
					 *
					 * @since 1.0.0
					 *
					 * @param array $form Form.
					 */
					do_action( 'wpforms_builder_preview', $this->form ); // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
					?>
				</div>

				<?php
					$captcha_settings = wpforms_get_captcha_settings();
					$extra_class      = 'is-' . $captcha_settings['provider'];
				?>

				<div class="wpforms-field-recaptcha <?php echo sanitize_html_class( $extra_class ); ?>">
					<div class="wpforms-field-recaptcha-wrap">
						<div class="wpforms-field-recaptcha-wrap-l">
							<svg class="wpforms-field-hcaptcha-icon" fill="none" viewBox="0 0 83 90"><path opacity=".5" d="M60.012 69.998H50.01V80h10.002V69.998z" fill="#0074BF"/><path opacity=".7" d="M50.01 69.998H40.008V80H50.01V69.998zM40.008 69.998H30.006V80h10.002V69.998z" fill="#0074BF"/><path opacity=".5" d="M30.006 69.998H20.004V80h10.002V69.998z" fill="#0074BF"/><path opacity=".7" d="M70.014 60.013H60.014v10.002h10.002V60.012z" fill="#0082BF"/><path opacity=".8" d="M60.012 60.013H50.01v10.002h10.002V60.012z" fill="#0082BF"/><path d="M50.01 60.013H40.008v10.002H50.01V60.012zM40.008 60.013H30.006v10.002h10.002V60.012z" fill="#0082BF"/><path opacity=".8" d="M30.006 60.013H20.004v10.002h10.002V60.012z" fill="#0082BF"/><path opacity=".7" d="M20.004 60.013H10.002v10.002h10.002V60.012z" fill="#0082BF"/><path opacity=".5" d="M80 50.01H69.998v10.002H80V50.01z" fill="#008FBF"/><path opacity=".8" d="M70.014 50.01H60.014v10.002h10.002V50.01z" fill="#008FBF"/><path d="M60.012 50.01H50.01v10.002h10.002V50.01zM50.01 50.01H40.008v10.002H50.01V50.01zM40.008 50.01H30.006v10.002h10.002V50.01zM30.006 50.01H20.004v10.002h10.002V50.01z" fill="#008FBF"/><path opacity=".8" d="M20.004 50.01H10.002v10.002h10.002V50.01z" fill="#008FBF"/><path opacity=".5" d="M10.002 50.01H0v10.002h10.002V50.01z" fill="#008FBF"/><path opacity=".7" d="M80 40.008H69.998V50.01H80V40.008z" fill="#009DBF"/><path d="M70.014 40.008H60.014V50.01h10.002V40.008zM60.012 40.008H50.01V50.01h10.002V40.008zM50.01 40.008H40.008V50.01H50.01V40.008zM40.008 40.008H30.006V50.01h10.002V40.008zM30.006 40.008H20.004V50.01h10.002V40.008zM20.004 40.008H10.002V50.01h10.002V40.008z" fill="#009DBF"/><path opacity=".7" d="M10.002 40.008H0V50.01h10.002V40.008z" fill="#009DBF"/><path opacity=".7" d="M80 30.006H69.998v10.002H80V30.006z" fill="#00ABBF"/><path d="M70.014 30.006H60.014v10.002h10.002V30.006zM60.012 30.006H50.01v10.002h10.002V30.006zM50.01 30.006H40.008v10.002H50.01V30.006zM40.008 30.006H30.006v10.002h10.002V30.006zM30.006 30.006H20.004v10.002h10.002V30.006zM20.004 30.006H10.002v10.002h10.002V30.006z" fill="#00ABBF"/><path opacity=".7" d="M10.002 30.006H0v10.002h10.002V30.006z" fill="#00ABBF"/><path opacity=".5" d="M80 20.004H69.998v10.002H80V20.004z" fill="#00B9BF"/><path opacity=".8" d="M70.014 20.004H60.014v10.002h10.002V20.004z" fill="#00B9BF"/><path d="M60.012 20.004H50.01v10.002h10.002V20.004zM50.01 20.004H40.008v10.002H50.01V20.004zM40.008 20.004H30.006v10.002h10.002V20.004zM30.006 20.004H20.004v10.002h10.002V20.004z" fill="#00B9BF"/><path opacity=".8" d="M20.004 20.004H10.002v10.002h10.002V20.004z" fill="#00B9BF"/><path opacity=".5" d="M10.002 20.004H0v10.002h10.002V20.004z" fill="#00B9BF"/><path opacity=".7" d="M70.014 10.002H60.014v10.002h10.002V10.002z" fill="#00C6BF"/><path opacity=".8" d="M60.012 10.002H50.01v10.002h10.002V10.002z" fill="#00C6BF"/><path d="M50.01 10.002H40.008v10.002H50.01V10.002zM40.008 10.002H30.006v10.002h10.002V10.002z" fill="#00C6BF"/><path opacity=".8" d="M30.006 10.002H20.004v10.002h10.002V10.002z" fill="#00C6BF"/><path opacity=".7" d="M20.004 10.002H10.002v10.002h10.002V10.002z" fill="#00C6BF"/><path opacity=".5" d="M60.012 0H50.01v10.002h10.002V0z" fill="#00D4BF"/><path opacity=".7" d="M50.01 0H40.008v10.002H50.01V0zM40.008 0H30.006v10.002h10.002V0z" fill="#00D4BF"/><path opacity=".5" d="M30.006 0H20.004v10.002h10.002V0z" fill="#00D4BF"/><path d="M26.34 36.84l2.787-6.237c1.012-1.592.88-3.55-.232-4.66a3.6 3.6 0 00-.481-.399 3.053 3.053 0 00-2.571-.298 4.246 4.246 0 00-2.322 1.791s-3.816 8.907-5.242 12.905c-1.426 3.998-.863 11.346 4.611 16.836 5.806 5.806 14.215 7.132 19.573 3.102.232-.116.431-.25.63-.415l16.521-13.8c.797-.664 1.99-2.024.93-3.583-1.046-1.526-3.003-.481-3.816.033l-9.504 6.917a.421.421 0 01-.597-.05s0-.017-.017-.017c-.249-.298-.282-1.078.1-1.393l14.58-12.374c1.26-1.128 1.426-2.787.414-3.915-.995-1.11-2.57-1.078-3.848.067l-13.12 10.267a.578.578 0 01-.813-.083c0-.016-.017-.016-.017-.033-.265-.298-.365-.78-.066-1.078l14.862-14.414c1.178-1.095 1.244-2.936.15-4.097a2.824 2.824 0 00-2.024-.863 2.905 2.905 0 00-2.09.83L39.544 36.144c-.365.364-1.078 0-1.161-.432a.474.474 0 01.132-.431l11.628-13.237a2.86 2.86 0 00.15-4.047 2.86 2.86 0 00-4.048-.15c-.05.05-.1.084-.133.133L28.447 37.47c-.63.63-1.56.664-2.007.299a.657.657 0 01-.1-.929z" fill="#fff"/></svg>
							<svg class="wpforms-field-recaptcha-icon" viewBox="0 0 28 27.918"><path d="M28 13.943l-.016-.607V2l-3.133 3.134a13.983 13.983 0 00-21.964.394l5.134 5.183a6.766 6.766 0 012.083-2.329A6.171 6.171 0 0114.025 7.1a1.778 1.778 0 01.492.066 6.719 6.719 0 015.17 3.119l-3.625 3.641 11.941.016" fill="#1c3aa9"/><path d="M13.943 0l-.607.016H2.018l3.133 3.133a13.969 13.969 0 00.377 21.964l5.183-5.134A6.766 6.766 0 018.382 17.9 6.171 6.171 0 017.1 13.975a1.778 1.778 0 01.066-.492 6.719 6.719 0 013.117-5.167l3.641 3.641L13.943 0" fill="#4285f4"/><path d="M0 13.975l.016.607v11.334l3.133-3.133a13.983 13.983 0 0021.964-.394l-5.134-5.183a6.766 6.766 0 01-2.079 2.33 6.171 6.171 0 01-3.92 1.279 1.778 1.778 0 01-.492-.066 6.719 6.719 0 01-5.167-3.117l3.641-3.641c-4.626 0-9.825.016-11.958-.016" fill="#ababab"/></svg>
							<svg class="wpforms-field-turnstile-icon" fill="none" viewBox="0 0 106 106"> <g clip-path="url(#a)"> <path fill="#F4801F" d="m72.375 76.265.541-1.877c.643-2.231.405-4.29-.678-5.808-1.011-1.397-2.66-2.216-4.68-2.312l-38.213-.486a.743.743 0 0 1-.683-1.012 1.012 1.012 0 0 1 .885-.678l38.583-.506c4.554-.207 9.532-3.92 11.267-8.454l2.196-5.748a1.354 1.354 0 0 0 .061-.779 25.13 25.13 0 0 0-48.312-2.6 11.307 11.307 0 0 0-17.708 11.849A16.054 16.054 0 0 0 .172 76.28a.744.744 0 0 0 .734.643H71.48a.927.927 0 0 0 .895-.658Z"/> <path fill="#F9AB41" d="M85.11 49.82c-.338 0-.692.01-1.063.03a.444.444 0 0 0-.162.035.59.59 0 0 0-.384.405l-1.518 5.191c-.648 2.231-.41 4.29.678 5.808a5.895 5.895 0 0 0 4.675 2.313l8.15.505a.728.728 0 0 1 .577.314.759.759 0 0 1 .086.693 1.012 1.012 0 0 1-.885.678l-8.465.506c-4.599.213-9.552 3.921-11.287 8.45l-.612 1.598a.455.455 0 0 0 .4.617h29.157a.782.782 0 0 0 .779-.592 20.92 20.92 0 0 0-10.822-24.36 20.916 20.916 0 0 0-9.294-2.191h-.01Z"/> </g> <defs> <clipPath id="a"> <path fill="#fff" d="M0 0h106v106H0z"/> </clipPath> </defs> </svg>
						</div>
						<div class="wpforms-field-recaptcha-wrap-r">
							<p class="wpforms-field-hcaptcha-title">hCaptcha</p>
							<p class="wpforms-field-recaptcha-title">reCAPTCHA</p>
							<p class="wpforms-field-turnstile-title">Turnstile</p>
							<p class="wpforms-field-recaptcha-desc">
								<span class="wpforms-field-recaptcha-desc-txt"><?php esc_html_e( 'Enabled', 'wpforms-lite' ); ?></span><svg class="wpforms-field-recaptcha-desc-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M512 256c0-37.7-23.7-69.9-57.1-82.4 14.7-32.4 8.8-71.9-17.9-98.6-26.7-26.7-66.2-32.6-98.6-17.9C325.9 23.7 293.7 0 256 0s-69.9 23.7-82.4 57.1c-32.4-14.7-72-8.8-98.6 17.9-26.7 26.7-32.6 66.2-17.9 98.6C23.7 186.1 0 218.3 0 256s23.7 69.9 57.1 82.4c-14.7 32.4-8.8 72 17.9 98.6 26.6 26.6 66.1 32.7 98.6 17.9 12.5 33.3 44.7 57.1 82.4 57.1s69.9-23.7 82.4-57.1c32.6 14.8 72 8.7 98.6-17.9 26.7-26.7 32.6-66.2 17.9-98.6 33.4-12.5 57.1-44.7 57.1-82.4zm-144.8-44.25L236.16 341.74c-4.31 4.28-11.28 4.25-15.55-.06l-75.72-76.33c-4.28-4.31-4.25-11.28.06-15.56l26.03-25.82c4.31-4.28 11.28-4.25 15.56.06l42.15 42.49 97.2-96.42c4.31-4.28 11.28-4.25 15.55.06l25.82 26.03c4.28 4.32 4.26 11.29-.06 15.56z"></path></svg>
							</p>
						</div>
					</div>
				</div>

				<?php
				$submit       = ! empty( $this->form_data['settings']['submit_text'] ) ? $this->form_data['settings']['submit_text'] : esc_html__( 'Submit', 'wpforms-lite' );
				$submit_style = empty( $this->form_data['fields'] ) ? 'display: none;' : '';

				printf( '<p class="wpforms-field-submit" style="%1$s"><input type="submit" value="%2$s" class="wpforms-field-submit-button"></p>', esc_attr( $submit_style ), esc_attr( $submit ) );

				/** This action is documented in includes/class-frontend.php. */
				do_action( 'wpforms_display_submit_after', $this->form_data, 'submit' ); // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
				?>

				<?php wpforms_debug_data( $this->form_data ); ?>
			</div>

		</div>

		<?php
	}

	/**
	 * Builder field buttons.
	 *
	 * @since 1.0.0
	 */
	public function fields(): void {

		$fields = wpforms_get_builder_fields();

		// Output the buttons.
		foreach ( $fields as $id => $group ) {

			usort( $group['fields'], [ $this, 'field_order' ] );

			echo '<div class="wpforms-add-fields-group">';

			echo '<a href="#" class="wpforms-add-fields-heading" data-group="' . esc_attr( $id ) . '">';

			echo '<span>' . esc_html( $group['group_name'] ) . '</span>';

			echo '<i class="fa fa-angle-down"></i>';

			echo '</a>';

			echo '<div class="wpforms-add-fields-buttons">';

			foreach ( $group['fields'] as $field ) {
				/**
				 * Attributes of the form field button on the Add Fields tab in the Form Builder.
				 *
				 * @since 1.5.1
				 *
				 * @param array $attributes Field attributes.
				 * @param array $field      Field data.
				 * @param array $form_data  Form data.
				 */
				$atts = apply_filters( // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
					'wpforms_builder_field_button_attributes',
					[
						'id'    => 'wpforms-add-fields-' . $field['type'],
						'class' => [ 'wpforms-add-fields-button' ],
						'data'  => [
							'field-type' => $field['type'],
						],
						'atts'  => [],
					],
					$field,
					$this->form_data
				);

				if ( ! empty( $field['keywords'] ) ) {
					$atts['data']['field-keywords'] = $field['keywords'];
				}

				if ( ! empty( $field['class'] ) ) {
					$atts['class'][] = $field['class'];
				}

				echo '<button ' . wpforms_html_attributes( $atts['id'], $atts['class'], $atts['data'], $atts['atts'] ) . '>';
					if ( $field['icon'] ) {
					echo '<i class="fa ' . esc_attr( $field['icon'] ) . '"></i> ';
					}
					echo esc_html( $field['name'] );
				echo '</button>';
			}

			echo '</div>';

			echo '</div>';
		}
	}

	/**
	 * Editor Field Options.
	 *
	 * @since 1.0.0
	 */
	public function fields_options(): void {

		// Check to make sure the form actually has fields created already.
		if ( empty( $this->form_data['fields'] ) ) {
			$this->no_fields_options();

			return;
		}

		$fields = $this->form_data['fields'];

		foreach ( $fields as $field ) {

			/**
			 * Filters the class attribute of the field option container in the Form Builder.
			 *
			 * @since 1.3.0
			 *
			 * @param string $class Field option class.
			 * @param array  $field Field data.
			 */
			$class = apply_filters( 'wpforms_builder_field_option_class', '', $field ); // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName

			printf( '<div class="wpforms-field-option wpforms-field-option-%s %s" id="wpforms-field-option-%d" data-field-id="%d">', sanitize_html_class( $field['type'] ), wpforms_sanitize_classes( $class ), (int) $field['id'], (int) $field['id'] );

			printf( '<input type="hidden" name="fields[%d][id]" value="%d" class="wpforms-field-option-hidden-id">', (int) $field['id'], (int) $field['id'] );

			printf( '<input type="hidden" name="fields[%d][type]" value="%s" class="wpforms-field-option-hidden-type">', (int) $field['id'], esc_attr( $field['type'] ) );

			/**
			 * Fires after the field option container in the Form Builder.
			 *
			 * @since 1.0.0
			 *
			 * @param array $field Field data.
			 */
			do_action( "wpforms_builder_fields_options_{$field['type']}", $field ); // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName

			echo '</div>';
		}
	}

	/**
	 * Editor preview (right pane).
	 *
	 * @since 1.0.0
	 */
	public function preview(): void {

		// Check to make sure the form actually has fields created already.
		if ( empty( $this->form_data['fields'] ) ) {
			$this->no_fields_preview();

			return;
		}

		/**
		 * Filters the fields which must be displayed on the base level on the preview panel in the Form Builder.
		 *
		 * @since 1.7.7
		 *
		 * @param array $fields Form fields data.
		 */
		$fields = (array) apply_filters( 'wpforms_builder_panel_fields_preview_fields', $this->form_data['fields'] );

		foreach ( $fields as $field ) {

			$this->preview_single_field(
				$field,
				[]
			);
		}
	}

	/**
	 * Preview a single field.
	 *
	 * @since 1.7.7
	 *
	 * @param array $field Field data.
	 * @param array $args  Additional arguments.
	 *
	 * @noinspection PhpMissingParamTypeInspection
	 * @noinspection PhpUnusedParameterInspection
	 */
	public function preview_single_field( $field, $args ): void { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh

		$class  = ! empty( $field['size'] ) ? 'size-' . esc_attr( $field['size'] ) : '';
		$class .= ! empty( $field['label_hide'] ) ? ' label_hide' : '';
		$class .= ! empty( $field['read_only'] ) ? ' readonly' : '';
		$class .= isset( $field['label'] ) && empty( $field['label'] ) && ! in_array( $field['type'], [ 'html', 'content' ], true ) ? ' label_empty' : '';
		$class .= ! empty( $field['sublabel_hide'] ) ? ' sublabel_hide' : '';
		$class .= ! empty( $field['required'] ) ? ' required' : '';
		$class .= isset( $field['meta']['delete'] ) && $field['meta']['delete'] === false ? ' no-delete' : '';
		$class .= isset( $field['meta']['duplicate'] ) && $field['meta']['duplicate'] === false ? ' no-duplicate' : '';

		if ( ! empty( $field['input_columns'] ) ) {
			$class .= $field['input_columns'] === '2' ? ' wpforms-list-2-columns' : '';
			$class .= $field['input_columns'] === '3' ? ' wpforms-list-3-columns' : '';
			$class .= $field['input_columns'] === 'inline' ? ' wpforms-list-inline' : '';
		}

		/**
		 * Filters class attribute of the field preview container in the Form Builder.
		 *
		 * @since 1.4.0
		 *
		 * @param string $css   Field preview class.
		 * @param array  $field Field data.
		 */
		$class = apply_filters( 'wpforms_field_preview_class', $class, $field ); // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName

		if ( ! has_action( "wpforms_display_field_{$field['type']}" ) ) {
			$this->unavailable_fields_preview( $field );

			return;
		}

		printf(
			'<div class="wpforms-field wpforms-field-%1$s %2$s" id="wpforms-field-%3$s" data-field-id="%3$s" data-field-type="%1$s">',
			esc_attr( $field['type'] ),
			esc_attr( $class ),
			wpforms_validate_field_id( $field['id'] )
		);

		/**
		 * Filters display the field duplicate button flag.
		 *
		 * @since 1.5.6.2
		 *
		 * @param bool  $display_duplicate_button Display field duplicate button flag.
		 * @param array $field                    Field data.
		 * @param array $form_data                Form data.
		 */
		if ( apply_filters( 'wpforms_field_preview_display_duplicate_button', true, $field, $this->form_data ) ) { // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
			printf(
				'<a href="#" class="wpforms-field-duplicate" title="%s"><i class="fa fa-files-o" aria-hidden="true"></i></a>',
				esc_attr__( 'Duplicate Field', 'wpforms-lite' )
			);
		}

		printf(
			'<a href="#" class="wpforms-field-delete" title="%s"><i class="fa fa-trash-o" aria-hidden="true"></i></a>',
			esc_attr__( 'Delete Field', 'wpforms-lite' )
		);

		// Multi-field actions menu.
		echo $this->get_multi_field_menu_html(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped

		if ( empty( $_COOKIE['wpforms_field_helper_hide'] ) ) {
			printf(
				'<div class="wpforms-field-helper">
						<span class="wpforms-field-helper-edit">%s</span>
						<span class="wpforms-field-helper-drag">%s</span>
						<span class="wpforms-field-helper-hide" title="%s">
							<i class="fa fa-times-circle" aria-hidden="true"></i>
						</span>
					</div>',
				esc_html__( 'Click to Edit', 'wpforms-lite' ),
				esc_html__( 'Drag to Reorder', 'wpforms-lite' ),
				esc_attr__( 'Hide Helper', 'wpforms-lite' )
			);
		}

		/**
		 * Fires after the field preview output in the Form Builder.
		 *
		 * @since 1.0.0
		 *
		 * @param array $field Field data.
		 */
		do_action( "wpforms_builder_fields_previews_{$field['type']}", $field ); // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName

		echo '</div>';
	}

	/**
	 * Generate HTML for hidden inputs from given data.
	 *
	 * @since 1.6.7
	 *
	 * @param array  $data Field array data.
	 * @param string $name Input name prefix.
	 */
	private function generate_hidden_inputs( $data = [], string $name = '' ): void {

		if ( ! is_array( $data ) || empty( $data ) ) {
			return;
		}

		foreach ( $data as $key => $value ) {
			if ( $key === 'id' ) {
				continue;
			}

			$key = ! empty( $data['id'] ) ? sprintf( '[%s][%s]', $data['id'], $key ) : sprintf( '[%s]', $key );

			if ( ! empty( $name ) ) {
				$key = trim( $name ) . $key;
			}

			if ( is_array( $value ) ) {
				$this->generate_hidden_inputs( $value, $key );
			} else {
				printf( "<input type='hidden' name='%s' value='%s' />",  esc_attr( $key ), esc_attr( $value ) );
			}
		}
	}

	/**
	 * Unavailable builder field display.
	 *
	 * @since 1.6.7
	 *
	 * @param array $field Field array data.
	 *
	 * @noinspection HtmlUnknownTarget
	 */
	public function unavailable_fields_preview( array $field ): void {

		// Using ucwords() for certain fields may generate incorrect words.
		switch ( $field['type'] ) {
			case 'url':
				$field_type = 'URL';
				break;

			case 'html':
				$field_type = 'HTML';
				break;

			case 'gdpr-checkbox':
				$field_type = 'GDPR Checkbox';
				break;

			default:
				$field_type = ucwords( preg_replace( '/[_-]/', ' ', $field['type'] ) );
		}

		$warning_message = sprintf( /* translators: %s - unavailable field name. */
			esc_html__( 'Unfortunately, the %s field is not available and will be ignored on the front end.', 'wpforms-lite' ),
			'<b>' . $field_type . '</b>'
		);

		$field_id = $field['id'] ?? 0;

		printf(
			'<div class="wpforms-alert wpforms-alert-warning wpforms-alert-dismissible wpforms-alert-field-not-available" data-field-id="%s" data-field-type="unavailable">',
			wpforms_validate_field_id( $field['id'] )
		);

		printf(
			'<div class="wpforms-alert-message">
				<p>%1$s</p>
			</div>
			<div class="wpforms-alert-buttons">
				<a href="%2$s" target="_blank" rel="noopener noreferrer" class="wpforms-btn wpforms-btn-md wpforms-btn-light-grey">%3$s</a>
				<button type="button" class="wpforms-dismiss-button" title="%4$s" data-field-id="%5$s" />
			</div>',
			$warning_message, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
			'https://wpforms.com/docs/how-to-import-and-export-wpforms/#field-missing',
			esc_html__( 'Learn More', 'wpforms-lite' ),
			esc_attr__( 'Dismiss this message. The field will be deleted as well.', 'wpforms-lite' ),
			wpforms_validate_field_id( $field_id )
		);

		// Save unavailable fields data in hidden inputs.
		$this->generate_hidden_inputs( $field, 'fields' );

		echo '</div>';
	}

	/**
	 * No fields options markup.
	 *
	 * @since 1.6.0
	 */
	public function no_fields_options(): void {

		printf(
			'<p class="no-fields wpforms-alert wpforms-alert-warning">%s</p>',
			esc_html__( 'You don\'t have any fields yet.', 'wpforms-lite' )
		);
	}

	/**
	 * No fields preview placeholder markup.
	 *
	 * @since 1.6.0
	 */
	public function no_fields_preview(): void {

		printf(
			'<div class="no-fields-preview">
				<h4>%1$s</h4>
				<p>%2$s</p>
			</div>',
			esc_html__( 'You don\'t have any fields yet. Add some!', 'wpforms-lite' ),
			esc_html__( 'Take your pick from our wide variety of fields and start building out your form!', 'wpforms-lite' )
		);
	}

	/**
	 * Sort Add Field buttons by order provided.
	 *
	 * @since 1.0.0
	 *
	 * @param array $a First item.
	 * @param array $b Second item.
	 *
	 * @return int
	 */
	public function field_order( array $a, array $b ): int {

		return $a['order'] - $b['order'];
	}

	/**
	 * Template for form builder preview.
	 *
	 * @since 1.4.5
	 */
	public function field_preview_templates(): void {

		// Checkbox, Radio, and Payment Multiple/Checkbox field choices.
		?>
		<script type="text/html" id="tmpl-wpforms-field-preview-checkbox-radio-payment-multiple">
			<# if ( data.settings.choices_images ) { #>
			<ul class="primary-input wpforms-image-choices wpforms-image-choices-{{ data.settings.choices_images_style }}">
				<# _.each( data.order, function( choiceID, key ) {  #>
				<li class="wpforms-image-choices-item<# if ( 1 === data.settings.choices[choiceID].default ) { print( ' wpforms-selected' ); } #>">
					<label>
						<span class="wpforms-image-choices-image">
							<# if ( ! _.isEmpty( data.settings.choices[choiceID].image ) ) { #>
							<img src="{{ data.settings.choices[choiceID].image }}" alt="{{ data.settings.choices[choiceID].label }}" title="{{ data.settings.choices[choiceID].label }}">
							<# } else { #>
							<img src="{{ wpforms_builder.image_placeholder }}" alt="{{ data.settings.choices[choiceID].label }}" title="{{ data.settings.choices[choiceID].label }}">
							<# } #>
						</span>
						<# if ( 'none' === data.settings.choices_images_style ) { #>
							<br>
							<input type="{{ data.type }}" readonly<# if ( 1 === data.settings.choices[choiceID].default ) { print( ' checked' ); } #>>
						<# } else { #>
							<input class="wpforms-screen-reader-element" type="{{ data.type }}" readonly<# if ( 1 === data.settings.choices[choiceID].default ) { print( ' checked' ); } #>>
						<# } #>
						<span class="wpforms-image-choices-label">
							{{{ WPFormsBuilder.fieldChoiceLabel( data, choiceID ) }}}
						</span>
					</label>
				</li>
				<# }) #>
			</ul>
			<# } else if ( data.settings.choices_icons ) { #>
			<ul class='primary-input wpforms-icon-choices wpforms-icon-choices-{{ data.settings.choices_icons_style }} wpforms-icon-choices-{{ data.settings.choices_icons_size }}' style="--wpforms-icon-choices-color: {{ data.settings.choices_icons_color }};">
				<# _.each( data.order, function( choiceID, key ) { #>
				<li class="wpforms-icon-choices-item<# if ( 1 === data.settings.choices[choiceID].default ) { print( ' wpforms-selected' ); } #>">
					<label>
						<span class="wpforms-icon-choices-icon">
							<i class="ic-fa-{{ data.settings.choices[choiceID].icon_style }} ic-fa-{{ data.settings.choices[choiceID].icon }}"></i>
							<span class="wpforms-icon-choices-icon-bg"></span>
						</span>
						<# if ( 'none' === data.settings.choices_icons_style ) { #>
							<input type='{{ data.type }}' readonly<# if ( 1 === data.settings.choices[choiceID].default ) { print( ' checked' ); } #>>
						<# } else { #>
							<input class='wpforms-screen-reader-element' type='{{ data.type }}' readonly<# if ( 1 === data.settings.choices[choiceID].default ) { print( ' checked' ); } #>>
						<# } #>
						<span class='wpforms-icon-choices-label'>
							{{{ WPFormsBuilder.fieldChoiceLabel( data, choiceID ) }}}
						</span>
					</label>
				</li>
				<# }) #>
			</ul>
			<# } else { #>
			<ul class="primary-input">
				<# _.each( data.order, function( choiceID, key ) {  #>
				<li>
					<input type="{{ data.type }}" readonly<# if ( 1 === data.settings.choices[choiceID].default ) { print( ' checked' ); } #>>
					{{{ WPFormsBuilder.fieldChoiceLabel( data, choiceID ) }}}
				</li>
				<# }) #>
			</ul>
			<# } #>
		</script>
		<?php
	}

	/**
	 * Template for form builder preview.
	 *
	 * @since 1.6.9
	 */
	public function choices_limit_message_template(): void {

		?>
		<script type="text/html" id="tmpl-wpforms-choices-limit-message">
			<div class="wpforms-alert-dynamic wpforms-alert wpforms-alert-warning">
				<?php
				printf(
					wp_kses( /* translators: %s - total number of choices. */
						__( 'Showing the first 20 choices.<br> All %s choices will be displayed when viewing the form.', 'wpforms-lite' ),
						[
							'br' => [],
						]
					),
					'{{ data.total }}'
				);
				?>
			</div>
		</script>
		<?php
	}

	/**
	 * Template for an empty choices message.
	 *
	 * @since 1.8.2
	 *
	 * @return void
	 */
	public function choices_empty_message_template(): void {

		?>
		<script type="text/html" id="tmpl-wpforms-empty-choice-message">
			<div class="wpforms-notice-dynamic-empty wpforms-alert wpforms-alert-warning">
				{{ data.message }}
			</div>
		</script>
		<?php
	}

	/**
	 * Builder fields search.
	 *
	 * @since 1.8.3
	 */
	public function search(): void {
		?>
		<div class="wpforms-search-fields-wrapper">
			<div class="wpforms-search-fields-input-wrapper">
				<label for="wpforms-search-fields-input" class="wpforms-screen-reader-element"><?php esc_html_e( 'Search fields:', 'wpforms-lite' ); ?></label>
				<input type="search" id="wpforms-search-fields-input" placeholder="<?php echo esc_attr__( 'Search fields...', 'wpforms-lite' ); ?>" autocomplete="off">
				<i class="fa fa-times wpforms-search-fields-input-close" aria-hidden="true"></i>
			</div>

			<div class="wpforms-search-fields-list">
				<div class="wpforms-add-fields-group">
					<div class="wpforms-add-fields-buttons"></div>
				</div>
			</div>

			<div class="wpforms-search-fields-no-results">
				<p>
					<?php esc_html_e( "Sorry, we didn't find any fields that match your criteria.", 'wpforms-lite' ); ?>
				</p>
			</div>
		</div>
		<?php
	}
}

new WPForms_Builder_Panel_Fields();
