/**
 * Custom Fields - field group builder (repeater, location switching, validation helpers).
 */
(function ($) {
	'use strict';

	var data = window.wppsCf || {};
	var strings = data.strings || {};
	var choiceTypes = data.choiceTypes || ['select', 'radio', 'checkbox', 'button_group'];
	var mediaTypes = data.mediaTypes || ['image', 'file', 'gallery'];
	var multipleTypes = data.multipleTypes || ['select', 'post_object', 'page_link', 'user'];
	var displayOnlyTypes = data.displayOnlyTypes || ['message', 'tab', 'accordion'];
	var nestedTypes = data.nestedTypes || ['group', 'repeater', 'flexible_content', 'clone'];
	var relationalTypes = data.relationalTypes || ['post_object', 'relationship', 'term', 'user'];
	var publicOutputTypes = data.publicOutputTypes || [];
	if (!publicOutputTypes.length && data.fieldTypes) {
		publicOutputTypes = Object.keys(data.fieldTypes).filter(function (type) {
			return displayOnlyTypes.indexOf(type) === -1 && nestedTypes.indexOf(type) === -1 && type !== 'password';
		});
	}
	var allowedSubTypes = data.allowedSubTypes || ['text', 'textarea', 'number', 'email', 'url'];
	var supports = data.supports || {};
	var returnFormats = data.returnFormats || {};
	var locationRuleOperators = data.locationRuleOperators || {};
	var numericLocationRuleParams = data.numericLocationRuleParams || ['post_id', 'post_parent', 'user_id', 'term_id'];
	var limits = data.limits || {};

	function typeSupports(type, setting) {
		return Array.isArray(supports[setting]) && supports[setting].indexOf(type) !== -1;
	}

	function configuredLimit(key, fallback) {
		var value = parseInt(limits[key], 10);
		return !isNaN(value) && value > 0 ? value : fallback;
	}

	function showLimitMessage(message) {
		var $notice = $('.cf-builder-feedback').first();
		if (!$notice.length) {
			$notice = $('<div class="cf-builder-feedback" role="status" aria-live="polite" hidden></div>');
			$('.cf-card--fields .cf-card__head').first().after($notice);
		}

		window.clearTimeout($notice.data('cfTimer'));
		$notice
			.text(message)
			.prop('hidden', false)
			.addClass('is-visible');

		$notice.data(
			'cfTimer',
			window.setTimeout(function () {
				$notice.removeClass('is-visible').prop('hidden', true);
			}, 5000)
		);
	}

	function initTooltips() {
		if (typeof window.wppsAccordionTooltipsInit === 'function') {
			window.wppsAccordionTooltipsInit();
		}
	}
	var nextIndex = 0;
	var nextLocRuleIndex = 0;

	function slugify(value) {
		return String(value)
			.toLowerCase()
			.replace(/[^a-z0-9_]+/g, '_')
			.replace(/^_+|_+$/g, '')
			.replace(/^([0-9])/, 'f_$1');
	}

	function escapeHtml(value) {
		return $('<div>').text(value == null ? '' : String(value)).html();
	}

	function fieldTypeLabel(type) {
		if (data.fieldTypes && data.fieldTypes[type] && data.fieldTypes[type].label) {
			return data.fieldTypes[type].label;
		}

		return String(type || '');
	}

	function randomSuffix(length) {
		var len = length || 13;
		var chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
		var out = '';
		for (var i = 0; i < len; i++) {
			out += chars.charAt(Math.floor(Math.random() * chars.length));
		}
		return out;
	}

	function generateGroupKey() {
		return ('group_' + randomSuffix(13)).substring(0, 64);
	}

	function generateFieldKey(label, $row) {
		var slug = slugify(label);
		if (!slug) {
			return '';
		}
		return uniqueFieldKey(slug, $row);
	}

	function existingFieldKeys($currentRow) {
		var keys = {};
		$('#cf-fields-list .cf-field-row').each(function () {
			var $row = $(this);
			var key;
			if ($currentRow && $row[0] === $currentRow[0]) {
				return;
			}
			key = ($row.find('.cf-field-key-input').first().val() || '').trim();
			if (!key) {
				key = ($row.find('.cf-field-key-readonly').first().text() || '').trim();
			}
			if (key) {
				keys[key] = true;
			}
		});
		return keys;
	}

	function uniqueFieldKey(slug, $row) {
		var keys = existingFieldKeys($row);
		var base = String(slug || '').substring(0, 64);
		var candidate = base;
		var suffix;
		var i;

		if (candidate && !keys[candidate]) {
			return candidate;
		}

		for (i = 2; i < 1000; i++) {
			suffix = '_' + i;
			candidate = base.substring(0, 64 - suffix.length) + suffix;
			if (candidate && !keys[candidate]) {
				return candidate;
			}
		}

		return (base.substring(0, 58) + '_' + randomSuffix(5)).substring(0, 64);
	}

	function fieldStoresValue(type) {
		return displayOnlyTypes.indexOf(type) === -1;
	}

	function fieldCanRenderPublicly(type) {
		return publicOutputTypes.indexOf(type) !== -1;
	}

	function refreshFieldGridSpans($row) {
		$row.find('.cf-field-grid').each(function () {
			var $grid = $(this);
			var rowControls = [];
			var autoHidden = $grid.data('cfAutoHidden') === true;
			if (autoHidden) {
				$grid.prop('hidden', false).data('cfAutoHidden', false);
			}
			if ($grid.prop('hidden')) {
				$grid.children('.cf-field-control').css('grid-column', '');
				return;
			}

			var $controls = $grid.children('.cf-field-control').filter(function () {
				return !$(this).prop('hidden');
			});

			$grid.css('grid-template-columns', 'repeat(12, minmax(0, 1fr))');
			$grid.children('.cf-field-control').css('grid-column', '');
			if (!$controls.length) {
				$grid.prop('hidden', true).data('cfAutoHidden', true);
				return;
			}

			function flushRow() {
				var span;
				if (!rowControls.length) {
					return;
				}
				span = Math.floor(12 / rowControls.length);
				rowControls.forEach(function ($control) {
					$control.css('grid-column', 'span ' + span);
				});
				rowControls = [];
			}

			$controls.each(function () {
				var $control = $(this);
				if ($control.hasClass('cf-field-control--wide')) {
					flushRow();
					$control.css('grid-column', '1 / -1');
					return;
				}
				rowControls.push($control);
				if (rowControls.length === 3) {
					flushRow();
				}
			});
			flushRow();
		});
	}

	function syncHiddenSettingControls($row) {
		$row.find('[data-cf-auto-disabled-hidden="1"]').each(function () {
			$(this).prop('disabled', false).removeAttr('data-cf-auto-disabled-hidden');
		});

		$row.find('.cf-field-control[hidden], .cf-field-grid[hidden]').find(':input').each(function () {
			var $input = $(this);
			if ($input.prop('disabled')) {
				return;
			}
			$input.prop('disabled', true).attr('data-cf-auto-disabled-hidden', '1');
		});
	}

	function placeNestedBuilderSections($row) {
		var $basicPanel = $row.find('[data-cf-field-panel="basic"]').first();
		var $anchor = $basicPanel.find('.cf-field-grid--primary-values').first();
		var $sections;

		if (!$basicPanel.length || !$anchor.length) {
			return;
		}

		$sections = $row.find('.cf-field-nested, .cf-field-clone');
		$sections.each(function () {
			if ($.contains($basicPanel[0], this)) {
				$anchor = $(this);
				return;
			}
			$anchor.after(this);
			$anchor = $(this);
		});
	}

	function setControlValue($control, value) {
		var normalized = value == null ? '' : String(value);
		$control.val(normalized).attr('value', normalized);
	}

	function repairSaveHiddenFields($form) {
		if (!$form || !$form.length) {
			return;
		}

		setControlValue($form.children('input[name="action"]').first(), 'wpps_cf_save');
		$form.children('input[name="_wpnonce"]').first().each(function () {
			var nonce = $(this).attr('value') || $(this).val();
			if (nonce) {
				setControlValue($(this), nonce);
			}
		});
		$form.children('input[name="_wp_http_referer"]').first().each(function () {
			var referer = $(this).attr('value') || $(this).val() || window.location.pathname + window.location.search;
			setControlValue($(this), referer);
		});
		$form.children('input[name="original_key"]').first().each(function () {
			var originalKey = $(this).attr('value') || $(this).val() || '';
			if (!originalKey) {
				originalKey = $('[data-cf-group-key-readonly]').first().text().trim();
			}
			setControlValue($(this), originalKey);
		});
	}

	function hardRestoreFieldStorageKeys() {
		document.querySelectorAll('#cf-fields-list .cf-field-row').forEach(function (row) {
			var keyInput = row.querySelector('.cf-field-key-input');
			var nameInput = row.querySelector('.cf-field-name-input');
			var key = keyInput && keyInput.value ? keyInput.value.trim() : '';
			var label;
			if (!key) {
				key = (row.querySelector('.cf-field-key-readonly') || {}).textContent || '';
				key = key.trim();
			}
			if (!key || key === '—') {
				key = (row.querySelector('.cf-field-key-preview code') || {}).textContent || '';
				key = key.trim();
			}
			if (!key || key === '—') {
				label = row.querySelector('.cf-field-label-input');
				key = slugify(label && label.value ? label.value : '');
			}
			if (keyInput && key && key !== '—') {
				keyInput.value = key;
				keyInput.setAttribute('value', key);
			}
			if (nameInput && key && key !== '—') {
				nameInput.value = key;
				nameInput.setAttribute('value', key);
			}
		});
	}

	function fieldNamePrefix($row) {
		var name = $row.find('.cf-field-key-input').attr('name') || '';
		return name.replace(/\[key\]$/, '');
	}

	function syncFieldNameInput($row) {
		var type = $row.find('.cf-field-type-input').val() || $row.attr('data-field-type') || 'text';
		var $name = $row.find('.cf-field-name-input');
		if (!fieldStoresValue(type)) {
			$name.remove();
			return;
		}

		if (!$name.length) {
			var prefix = fieldNamePrefix($row);
			if (!prefix) {
				return;
			}
			$name = $('<input type="hidden" class="cf-field-name-input">')
				.attr('name', prefix + '[name]')
				.insertAfter($row.find('.cf-field-key-input'));
		}

		if (!$row.find('.cf-field-key-input').data('cfPersisted') || !$name.val()) {
			setControlValue($name, fieldRowGeneratedKey($row));
		}
	}

	function updateFieldKey($row) {
		var $key = $row.find('.cf-field-key-input');
		if (!$key.length || $key.data('manual') || $key.data('cfPersisted')) {
			if ($key.length && !$key.val()) {
				setControlValue($key, fieldRowGeneratedKey($row));
			}
			syncFieldNameInput($row);
			updateFieldKeyPreview($row);
			return;
		}
		var label = ($row.find('.cf-field-label-input').val() || '').trim();
		var generated = generateFieldKey(label, $row);
		setControlValue($key, generated);
		setControlValue($row.find('.cf-field-name-input').first(), generated);
		syncFieldNameInput($row);
		updateFieldKeyPreview($row);
	}

	function updateFieldKeyPreview($row) {
		var key = fieldRowGeneratedKey($row);
		$row.find('.cf-field-key-preview code').text(key || '—');
	}

	function fieldRowGeneratedKey($row) {
		var key = ($row.find('.cf-field-key-input').first().val() || '').trim();
		if (!key) {
			key = ($row.find('.cf-field-key-readonly').first().text() || '').trim();
		}
		if (!key || key === '—') {
			key = ($row.find('.cf-field-key-preview code').first().text() || '').trim();
		}
		return key === '—' ? '' : key;
	}

	function restorePersistedFieldKey($row) {
		var $key = $row.find('.cf-field-key-input').first();
		var key;
		if (!$key.length || $key.val()) {
			return;
		}

		key = ($row.find('.cf-field-key-readonly').first().text() || '').trim();
		if (!key || key === '—') {
			key = fieldRowGeneratedKey($row);
		}
		setControlValue($key, key);
	}

	function ensureFieldStorageKey($row) {
		var $key = $row.find('.cf-field-key-input').first();
		var key;
		if (!$key.length) {
			return '';
		}

		key = ($key.val() || '').trim();
		if (!key) {
			key = ($row.find('.cf-field-key-readonly').first().text() || '').trim();
		}
		if (!key || key === '—') {
			key = ($row.find('.cf-field-key-preview code').first().text() || '').trim();
		}
		if (!key || key === '—') {
			key = generateFieldKey(($row.find('.cf-field-label-input').first().val() || '').trim(), $row);
		}
		if (key && key !== '—') {
			setControlValue($key, key);
			setControlValue($row.find('.cf-field-name-input').first(), key);
			return key;
		}

		return '';
	}

	function restoreAllPersistedFieldKeys() {
		$('#cf-fields-list .cf-field-row').each(function () {
			var $row = $(this);
			var key;
			restorePersistedFieldKey($row);
			key = fieldRowGeneratedKey($row);
			if (key && !$row.find('.cf-field-name-input').first().val()) {
				setControlValue($row.find('.cf-field-name-input').first(), key);
			}
		});
	}

	function refreshReturnFormatOptions($row, type) {
		var $select = $row.find('.cf-field-return select');
		if (!$select.length) {
			return;
		}
		var current = String($select.val() || '');
		var options = returnFormats[type] || {};
		$select.empty();
		Object.keys(options).forEach(function (value) {
			$select.append($('<option>').val(value).text(options[value]));
		});
		if (current && Object.prototype.hasOwnProperty.call(options, current)) {
			$select.val(current);
		}
	}

	function computeNextIndex() {
		var max = -1;
		$('#cf-fields-list .cf-field-row').each(function () {
			var idx = parseInt($(this).attr('data-index'), 10);
			if (!isNaN(idx) && idx > max) {
				max = idx;
			}
		});
		nextIndex = max + 1;
	}

	function reindexFieldRow($row, index) {
		$row.attr('data-index', String(index));
		$row.find('[name]').each(function () {
			var name = $(this).attr('name');
			if (name) {
				$(this).attr('name', name.replace(/fields\[[^\]]+\]/, 'fields[' + index + ']'));
			}
		});
		$row.find('[data-cf-name]').each(function () {
			var dataName = $(this).attr('data-cf-name');
			if (dataName) {
				$(this).attr('data-cf-name', dataName.replace(/fields\[[^\]]+\]/, 'fields[' + index + ']'));
			}
		});
		$row.find('[id]').each(function () {
			var id = $(this).attr('id');
			if (id) {
				$(this).attr('id', id.replace(/^cf-field-[^-]+-/, 'cf-field-' + index + '-'));
			}
		});
		$row.find('label[for]').each(function () {
			var target = $(this).attr('for');
			if (target) {
				$(this).attr('for', target.replace(/^cf-field-[^-]+-/, 'cf-field-' + index + '-'));
			}
		});
	}

	function refreshFieldTypeUI($row) {
		var type = $row.find('.cf-field-type-input').val();
		var isDisplayOnly = displayOnlyTypes.indexOf(type) !== -1;

		restorePersistedFieldKey($row);
		$row.attr('data-field-type', type);
		$row.find('.cf-field-choices').prop('hidden', choiceTypes.indexOf(type) === -1);
		$row.find('.cf-field-multiple').prop('hidden', multipleTypes.indexOf(type) === -1);
		var $multipleInput = $row.find('.cf-field-multiple input[type="checkbox"]');
		if (type === 'relationship') {
			$multipleInput.prop('checked', true).prop('disabled', true).data('cfAutoMultiple', true);
		} else {
			if ($multipleInput.data('cfAutoMultiple')) {
				$multipleInput.prop('checked', false).data('cfAutoMultiple', false);
			}
			$multipleInput.prop('disabled', false);
		}
		refreshReturnFormatOptions($row, type);
		$row.find('.cf-field-return').prop('hidden', !typeSupports(type, 'return_format'));
		$row.find('.cf-field-message').prop('hidden', type !== 'message');
		$row.find('.cf-field-output').prop('hidden', type !== 'output');
		$row.find('.cf-field-bounds').prop('hidden', !typeSupports(type, 'bounds'));
		$row.find('.cf-field-rows').prop('hidden', !typeSupports(type, 'rows'));
		$row.find('.cf-field-new-lines').prop('hidden', !typeSupports(type, 'new_lines'));
		$row.find('.cf-field-date-display').prop('hidden', !typeSupports(type, 'date_display'));
		$row.find('.cf-field-date-save-format').prop(
			'hidden',
			!typeSupports(type, 'date_save_format') || !$row.find('.cf-field-date-save-format input').first().val()
		);
		$row.find('.cf-field-first-day').prop('hidden', !typeSupports(type, 'date_first_day'));
		$row.find('.cf-field-default-current').prop('hidden', !typeSupports(type, 'default_current'));
		$row.find('.cf-field-relationship-ui').prop('hidden', !typeSupports(type, 'relationship_filters'));
		$row.find('.cf-field-color-options').prop('hidden', !typeSupports(type, 'color_options'));
		$row.find('.cf-field-toggle-options').prop('hidden', !typeSupports(type, 'toggle_options'));
		$row.find('.cf-field-toggle-ui').prop('hidden', !typeSupports(type, 'toggle_ui'));
		$row.find('.cf-field-toggle-ui-text').prop('hidden', !typeSupports(type, 'toggle_ui') || !$row.find('.cf-field-toggle-ui-input').is(':checked'));
		$row.find('.cf-field-icon-tabs').prop('hidden', !typeSupports(type, 'icon_tabs'));
		$row.find('.cf-field-oembed-dimensions').prop('hidden', !typeSupports(type, 'oembed_dimensions'));
		$row.find('.cf-field-google-map-defaults').prop('hidden', !typeSupports(type, 'google_map_defaults'));
		$row.find('.cf-field-message-options').prop('hidden', !typeSupports(type, 'message_options'));
		$row.find('.cf-field-wysiwyg-options').prop('hidden', !typeSupports(type, 'wysiwyg_options'));
		$row.find('.cf-field-tab-options').prop('hidden', !typeSupports(type, 'tab_options'));
		$row.find('.cf-field-accordion-options').prop('hidden', !typeSupports(type, 'accordion_options'));
		$row.find('.cf-field-placeholder').prop('hidden', !typeSupports(type, 'placeholder'));
		$row.find('.cf-field-default').prop('hidden', !typeSupports(type, 'default'));
		syncDefaultValueControl($row, type);
		$row.find('.cf-field-maxlength').prop('hidden', !typeSupports(type, 'maxlength'));
		$row.find('.cf-field-allow-null').prop('hidden', !typeSupports(type, 'allow_null') || !taxonomySupportsAllowNull($row, type));
		$row.find('.cf-field-choice-layout').prop('hidden', !typeSupports(type, 'choice_layout'));
		$row.find('.cf-field-checkbox-toggle').prop('hidden', !typeSupports(type, 'checkbox_toggle'));
		$row.find('.cf-field-choice-custom').prop('hidden', !typeSupports(type, 'choice_custom'));
		$row.find('.cf-field-choice-save-custom').prop('hidden', !typeSupports(type, 'choice_custom') || !$row.find('.cf-field-allow-custom-input').is(':checked'));
		$row.find('.cf-field-select-options').prop('hidden', !typeSupports(type, 'select_options'));
		$row.find('.cf-field-nav-menu-options').prop('hidden', !typeSupports(type, 'nav_menu_container'));
		$row.find('.cf-field-select-ajax, .cf-field-select-create').prop('hidden', !typeSupports(type, 'select_options') || !$row.find('.cf-field-select-ui-input').is(':checked'));
		$row.find('.cf-field-select-save').prop('hidden', !typeSupports(type, 'select_options') || !$row.find('.cf-field-select-ui-input').is(':checked') || !$row.find('.cf-field-select-create-input').is(':checked'));
		$row.find('.cf-field-media-library').prop('hidden', !typeSupports(type, 'media_library'));
		$row.find('.cf-field-media-mime').prop('hidden', !typeSupports(type, 'media_mime'));
		$row.find('.cf-field-media-size').prop('hidden', !typeSupports(type, 'media_size'));
		$row.find('.cf-field-image-dimensions').prop('hidden', !typeSupports(type, 'image_dimensions'));
		$row.find('.cf-field-image-preview-size').prop('hidden', !typeSupports(type, 'image_preview_size'));
		$row.find('.cf-field-gallery-display').prop('hidden', !typeSupports(type, 'gallery_display'));
		$row.find('.cf-field-gallery-count').prop('hidden', !typeSupports(type, 'gallery_count'));
		$row.find('.cf-field-count').prop('hidden', !typeSupports(type, 'count'));
		$row.find('.cf-field-button-label').prop('hidden', !typeSupports(type, 'button_label'));
		$row.find('.cf-field-nested-layout').prop('hidden', !typeSupports(type, 'nested_layout'));
		$row.find('.cf-field-repeater-collapsed').prop('hidden', !typeSupports(type, 'repeater_collapsed'));
		$row.find('.cf-field-repeater-pagination').prop('hidden', !typeSupports(type, 'repeater_pagination'));
		$row.find('.cf-field-post-types').prop('hidden', ['post_object', 'relationship', 'page_link'].indexOf(type) === -1);
		$row.find('.cf-field-post-statuses').prop('hidden', !typeSupports(type, 'post_status_filter'));
		$row.find('.cf-field-allow-archives').prop('hidden', !typeSupports(type, 'allow_archives'));
		$row.find('.cf-field-taxonomy').prop('hidden', type !== 'term');
		$row.find('.cf-field-taxonomy-terms').prop('hidden', ['post_object', 'relationship', 'page_link'].indexOf(type) === -1);
		$row.find('.cf-field-taxonomy-type').prop('hidden', !typeSupports(type, 'taxonomy_field_type'));
		$row.find('.cf-field-taxonomy-sync').prop('hidden', !typeSupports(type, 'taxonomy_term_sync'));
		$row.find('.cf-field-taxonomy-create').prop('hidden', !typeSupports(type, 'taxonomy_term_create'));
		$row.find('.cf-field-user-roles').prop('hidden', !typeSupports(type, 'user_role'));
		$row.find('.cf-field-repeater').prop('hidden', ['group', 'repeater'].indexOf(type) === -1);
		$row.find('.cf-field-flexible').prop('hidden', type !== 'flexible_content');
		$row.find('.cf-field-clone').prop('hidden', type !== 'clone');
		$row.find('.cf-field-bidirectional').prop('hidden', relationalTypes.indexOf(type) === -1);
		$row.find('.cf-field-conditional').prop('hidden', isDisplayOnly);
		$row.find('.cf-field-before-after').prop('hidden', !typeSupports(type, 'before_after'));
		$row.find('.cf-field-storage, .cf-field-required').prop('hidden', isDisplayOnly);
		$row.find('.cf-field-show-list').prop('hidden', !fieldCanRenderPublicly(type));
		syncWysiwygOptions($row);
		placeNestedBuilderSections($row);
		refreshFieldGridSpans($row);
		syncHiddenSettingControls($row);

		syncFieldNameInput($row);
		updateFieldKeyPreview($row);

		var typeLabel = type;
		if (data.fieldTypes && data.fieldTypes[type]) {
			typeLabel = data.fieldTypes[type].label;
		}
		$row.find('.cf-field-row__type').text(typeLabel);
	}

	function usesMultiDefaultValue($row, type) {
		return type === 'checkbox' || (type === 'select' && $row.find('.cf-field-multiple input[type="checkbox"]').is(':checked'));
	}

	function taxonomySupportsAllowNull($row, type) {
		if (type !== 'term') {
			return true;
		}
		return $row.find('select[name$="[taxonomy_field_type]"]').val() !== 'checkbox';
	}

	function syncDefaultValueControl($row, type) {
		var supportsDefault = typeSupports(type, 'default');
		var usesTextarea = usesMultiDefaultValue($row, type);
		var usesToggle = type === 'toggle';
		$row.find('.cf-field-default-input').prop('hidden', !supportsDefault || usesTextarea || usesToggle).prop('disabled', !supportsDefault || usesTextarea || usesToggle);
		$row.find('.cf-field-default-textarea').prop('hidden', !supportsDefault || !usesTextarea).prop('disabled', !supportsDefault || !usesTextarea);
		$row.find('.cf-field-default-toggle').prop('hidden', !supportsDefault || !usesToggle);
		$row.find('.cf-field-default-toggle input').prop('disabled', !supportsDefault || !usesToggle);
	}

	function syncWysiwygOptions($row) {
		var type = $row.find('.cf-field-type-input').val();
		var isWysiwyg = type === 'wysiwyg';
		var tabs = $row.find('select[name$="[wysiwyg_tabs]"]').val() || 'all';
		var hideVisualOnlyOptions = !isWysiwyg || tabs === 'text';

		$row.find('.cf-field-wysiwyg-toolbar-control, .cf-field-wysiwyg-delay-control')
			.prop('hidden', hideVisualOnlyOptions);
		$row.find('.cf-field-wysiwyg-toolbar-control select, .cf-field-wysiwyg-delay-control input')
			.prop('disabled', hideVisualOnlyOptions);
	}

	function updateRowTitle($row) {
		var label = $row.find('.cf-field-label-input').val();
		$row.find('.cf-field-row__title').text(label && label.length ? label : strings.untitledField || 'Untitled field');
	}

	function defaultDisplayFormat(type) {
		if (type === 'date') {
			return 'd/m/Y';
		}
		if (type === 'time') {
			return 'g:i a';
		}
		if (type === 'datetime') {
			return 'd/m/Y g:i a';
		}
		return '';
	}

	function buildFieldKeyPreview() {
		return $('<span class="description cf-field-key-preview"></span>')
			.text((strings.fieldKeyPreview || 'Field key:') + ' ')
			.append($('<code></code>').text('—'));
	}

	function buildFieldsEmptyState() {
		return $('<div class="cf-fields-empty"></div>')
			.append($('<strong></strong>').text(strings.startWithQuickAdd || 'Start with Quick Add'))
			.append(
				$('<span></span>').text(
					strings.noFieldsYet || 'Choose a field type from the right, or use Add Field for a blank text field.'
				)
			);
	}

	function addField(type) {
		var fieldTpl = document.getElementById('cf-field-row-template');
		var template = fieldTpl ? (fieldTpl.innerHTML || '') : '';
		var maxFields = configuredLimit('maxFields', 200);
		if (!template) {
			return;
		}
		if ($('#cf-fields-list .cf-field-row').length >= maxFields) {
			showLimitMessage(strings.fieldLimitReached || 'This field group has reached the maximum number of fields.');
			return;
		}
		type = String(type || 'text');
		if (!data.fieldTypes || !data.fieldTypes[type]) {
			type = 'text';
		}
		computeNextIndex();
		var html = template.replace(/__INDEX__/g, String(nextIndex));
		var $row = $(html);
		$('#cf-fields-list .cf-fields-empty').remove();
		$('#cf-fields-list .cf-field-row').addClass('collapsed').find('.cf-field-row__toggle').attr('aria-expanded', 'false');
		$('#cf-fields-list').append($row);
		$row.removeClass('collapsed');
		$row.find('.cf-field-row__toggle').attr('aria-expanded', 'true');
		$row.find('.cf-field-type-input').val(type);
		$row.find('.cf-field-label-input').val('');
		$row.find('.cf-field-return select').val('');
		if (type === 'button_group') {
			$row.find('select[name$="[choice_layout]"]').val('horizontal');
		}
		if (type === 'repeater') {
			$row.find('select[name$="[nested_layout]"]').val('table');
		}
		if (type === 'term') {
			$row.find('select[name$="[taxonomy]"]').val('category');
			$row.find('select[name$="[taxonomy_field_type]"]').val('checkbox');
		}
		$row.find('input[name$="[display_format]"]').val(defaultDisplayFormat(type));
		$row.find('input[name$="[taxonomy_add_terms]"]').prop('checked', type === 'term');
		refreshFieldTypeUI($row);
		updateFieldKey($row);
		updateRowTitle($row);
		if (window.wppsCfInitColorPickers) {
			window.wppsCfInitColorPickers($row);
		}
		initTooltips();
		refreshAllConditionalFieldSelects();
		refreshAllConditionalValueControls();
		$row.find('.cf-field-label-input').trigger('focus');
	}

	function computeNextLocRuleIndex() {
		var max = -1;
		$('#cf-location-rules-list .cf-rule-row').each(function () {
			var idx = parseInt($(this).attr('data-index'), 10);
			if (!isNaN(idx) && idx > max) {
				max = idx;
			}
		});
		nextLocRuleIndex = max + 1;
	}

	function syncLocationState() {
		var screen = $('#cf-loc-screen').val() || 'post';
		$('.cf-position-row, .cf-priority-row, .cf-style-row').prop('hidden', screen !== 'post');
	}

	function syncPositionPicker() {
		$('.cf-position-option').each(function () {
			$(this).toggleClass('is-selected', $(this).find('input[type="radio"]').is(':checked'));
		});
	}

	var ruleValueChoices = (function () {
		var el = document.getElementById('cf-rule-value-choices');
		if (!el) {
			return {};
		}
		try {
			return JSON.parse(el.innerHTML || el.textContent) || {};
		} catch (e) {
			return {};
		}
	})();

	function locationOperatorsForParam(param) {
		var all = data.ruleOperators || { '==': 'is equal to', '!=': 'is not equal to' };
		var allowed = locationRuleOperators[param] || ['==', '!='];
		var out = [];

		allowed.forEach(function (operator) {
			if (Object.prototype.hasOwnProperty.call(all, operator)) {
				out.push({ value: operator, label: all[operator] });
			}
		});

		if (!out.length) {
			out.push({ value: '==', label: all['=='] || 'is equal to' });
		}

		return out;
	}

	function syncRuleOperatorControl($row) {
		var param = $row.find('.cf-rule-param').val();
		var $operator = $row.find('.cf-rule-operator');
		var current = $operator.val() || '==';
		var operators = locationOperatorsForParam(param);
		var hasCurrent = false;

		$operator.empty();
		operators.forEach(function (operator) {
			if (operator.value === current) {
				hasCurrent = true;
			}
			$operator.append($('<option>').val(operator.value).text(operator.label));
		});
		$operator.val(hasCurrent ? current : operators[0].value);
	}

	/**
	 * Show a dropdown for parameters with known values (post type, taxonomy,
	 * template, status, role); a text input for ID-based parameters. The
	 * inactive control is disabled so only one submits.
	 */
	function syncRuleValueControl($row) {
		var param = $row.find('.cf-rule-param').val();
		var operator = $row.find('.cf-rule-operator').val();
		var noValue = operator === 'empty' || operator === 'not_empty';
		var choices = ruleValueChoices[param];
		var hasChoices = choices && Object.keys(choices).length > 0;
		var $select = $row.find('.cf-rule-value-select');
		var $input = $row.find('.cf-rule-value');
		var inputType = numericLocationRuleParams.indexOf(param) !== -1 ? 'number' : 'text';

		if ($input.attr('type') !== inputType) {
			$input.attr('type', inputType);
		}
		if (inputType === 'number') {
			$input.attr({ inputmode: 'numeric', step: '1', min: '0' });
		} else {
			$input.removeAttr('inputmode step min');
		}

		if (hasChoices) {
			// Keep the selection only while the parameter is unchanged
			// (or on the very first sync of a server-rendered row).
			var builtFor = $select.data('cfParam');
			var current = '';
			if (builtFor === param || (builtFor === undefined && !$select.prop('disabled'))) {
				current = $select.val() || '';
			}
			$select.empty();
			Object.keys(choices).forEach(function (val) {
				$select.append($('<option>').val(val).text(choices[val]));
			});
			if (current && !Object.prototype.hasOwnProperty.call(choices, current)) {
				$select.prepend($('<option>').val(current).text(current));
			}
			if (current) {
				$select.val(current);
			}
			$select.data('cfParam', param);
			$select.prop('hidden', noValue).prop('disabled', noValue);
			$input.prop('hidden', true).prop('disabled', true);
		} else {
			$input.prop('hidden', noValue).prop('disabled', noValue);
			$select.prop('hidden', true).prop('disabled', true);
		}
	}

	/**
	 * Parse a choices textarea ("value|Label" or "value : Label" per line) into an array of
	 * { value, label } objects, mirroring Validator::parseChoices().
	 */
	function parseChoiceLines(raw) {
		var out = [];
		String(raw || '').split(/\r\n|\r|\n/).forEach(function (line) {
			line = line.trim();
			if (!line) {
				return;
			}
			var value = line;
			var label = line;
			var pipe = line.indexOf('|');
			if (pipe !== -1) {
				value = line.slice(0, pipe).trim();
				label = line.slice(pipe + 1).trim() || value;
			} else {
				var colon = line.match(/^([^:]+)\s:\s(.+)$/);
				if (colon) {
					value = colon[1].trim();
					label = colon[2].trim() || value;
				}
			}
			if (value !== '') {
				out.push({ value: value, label: label });
			}
		});
		return out;
	}

	/** Find a top-level field row by its assigned field key. */
	function fieldRowByKey(key) {
		if (!key) {
			return null;
		}
		var $match = null;
		$('#cf-fields-list .cf-field-row').each(function () {
			var rowKey = fieldRowGeneratedKey($(this));
			if (rowKey === key) {
				$match = $(this);
				return false;
			}
		});
		return $match;
	}

	function canDriveConditionalLogic($row) {
		var type = String($row.find('.cf-field-type-input').first().val() || '');
		return displayOnlyTypes.indexOf(type) === -1 && nestedTypes.indexOf(type) === -1;
	}

	function conditionalFieldChoices($currentRow) {
		var choices = [];
		$('#cf-fields-list .cf-field-row').each(function () {
			if ($currentRow && this === $currentRow[0]) {
				return;
			}
			var $row = $(this);
			if (!canDriveConditionalLogic($row)) {
				return;
			}
			var key = fieldRowGeneratedKey($row);
			if (!key) {
				return;
			}
			var label = $row.find('.cf-field-label-input').first().val() || key;
			choices.push({ key: key, label: label + ' (' + key + ')' });
		});
		return choices;
	}

	function refreshConditionalFieldSelect($select, $currentRow) {
		var current = String($select.val() || '');
		$select.empty().append($('<option>').val('').text('\u2014'));
		conditionalFieldChoices($currentRow).forEach(function (choice) {
			$select.append($('<option>').val(choice.key).text(choice.label));
		});
		if (current) {
			if (!$select.find('option[value="' + current.replace(/"/g, '\\"') + '"]').length) {
				$select.append($('<option>').val(current).text(current));
			}
			$select.val(current);
		}
	}

	function refreshAllConditionalFieldSelects() {
		$('#cf-fields-list .cf-conditional-rule-row select[name$="[field]"]').each(function () {
			refreshConditionalFieldSelect($(this), $(this).closest('.cf-field-row'));
		});
	}

	function rewriteConditionalSourceKey(oldKey, newKey) {
		if (!oldKey || !newKey || oldKey === newKey) {
			return;
		}
		$('#cf-fields-list .cf-conditional-rule-row select[name$="[field]"]').each(function () {
			var $select = $(this);
			if (String($select.val() || '') === oldKey) {
				$select.find('option').filter(function () {
					return String($(this).val() || '') === oldKey;
				}).val(newKey);
				$select.val(newKey);
			}
		});
	}

	/** Available value choices for a trigger field (only choice-based types). */
	function conditionalValueChoices(depKey) {
		var $dep = fieldRowByKey(depKey);
		if (!$dep) {
			return [];
		}
		var type = String($dep.find('.cf-field-type-input').first().val() || '');
		if (type === 'toggle') {
			return [
				{ value: '1', label: strings.yes || 'Yes' },
				{ value: '0', label: strings.no || 'No' },
			];
		}
		if (choiceTypes.indexOf(type) === -1) {
			return [];
		}
		return parseChoiceLines($dep.find('textarea[name$="[choices]"]').first().val());
	}

	function conditionalOperatorNeedsValue(operator) {
		return operator !== 'empty' && operator !== 'not_empty';
	}

	/**
	 * Build the value control for a conditional rule: a dropdown of the trigger
	 * field's choices when available, a text input as a fallback, or a hidden
	 * input for value-less operators. Mirrors the Options Page Builder pattern.
	 */
	function buildConditionalValueControl(name, selected, depKey, operator) {
		selected = selected == null ? '' : String(selected);

		if (!conditionalOperatorNeedsValue(operator)) {
			return $('<input type="hidden" class="cf-conditional-value">').attr('name', name).val('');
		}

		if (!depKey) {
			return $('<select class="cf-conditional-value" disabled>').attr('name', name).append(
				$('<option>').val('').text(strings.condSelectField || 'Select a field first')
			);
		}

		var choices = conditionalValueChoices(depKey);
		if (!choices.length) {
			return $('<input type="text" class="regular-text cf-conditional-value">').attr('name', name).val(selected);
		}

		var $select = $('<select class="cf-conditional-value">').attr('name', name);
		$select.append($('<option>').val('').text(strings.condSelectValue || 'Select a value'));
		var matched = false;
		choices.forEach(function (choice) {
			var $opt = $('<option>').val(choice.value).text(choice.label);
			if (String(choice.value) === selected) {
				$opt.prop('selected', true);
				matched = true;
			}
			$select.append($opt);
		});
		if (selected && !matched) {
			$select.prepend($('<option>').val(selected).text(selected).prop('selected', true));
		}
		return $select;
	}

	/** Rebuild the value control inside a single conditional rule row. */
	function refreshConditionalValueControl($ruleRow) {
		var $wrap = $ruleRow.find('.cf-conditional-value-wrap');
		if (!$wrap.length) {
			return;
		}
		var name = $wrap.attr('data-cf-name') || '';
		var depKey = String($ruleRow.find('select[name$="[field]"]').first().val() || '');
		var operator = String($ruleRow.find('select[name$="[operator]"]').first().val() || '==');
		var current = $wrap.find('.cf-conditional-value').val();
		if (current == null || current === '') {
			current = $wrap.attr('data-cf-selected') || '';
		}
		$wrap.empty().append(buildConditionalValueControl(name, current, depKey, operator));
	}

	function refreshAllConditionalValueControls() {
		$('#cf-fields-list .cf-conditional-rule-row').each(function () {
			refreshConditionalValueControl($(this));
		});
	}

	function subFieldOptionsHtml() {
		return allowedSubTypes
			.map(function (t) {
				return '<option value="' + escapeHtml(t) + '">' + escapeHtml(fieldTypeLabel(t)) + '</option>';
			})
			.join('');
	}

	function widthOptionsHtml() {
		return [
			['100', 'Full width'],
			['75', 'Three quarters'],
			['50', 'Half width'],
			['33', 'One third'],
			['25', 'Quarter width'],
		]
			.map(function (item) {
				return '<option value="' + item[0] + '">' + escapeHtml(item[1]) + '</option>';
			})
			.join('');
	}

	function subFieldRowHtml(prefix, idx) {
		var labelText = strings.subFieldLabel || 'Label';
		var typeText = strings.subFieldType || 'Type';
		var keyText = strings.fieldKey || 'Field key';
		var removeText = strings.removeSubField || 'Remove sub field';

		return (
			'<div class="cf-subfield-row" data-index="' +
			idx +
			'"><label class="cf-subfield-row__control"><span>' +
			escapeHtml(typeText) +
			'</span><select name="' +
			prefix +
			'[sub_fields][' +
			idx +
			'][type]">' +
			subFieldOptionsHtml() +
			'</select></label><label class="cf-subfield-row__control"><span>' +
			escapeHtml(labelText) +
			'</span><input type="text" class="cf-subfield-label-input" name="' +
			prefix +
			'[sub_fields][' +
			idx +
			'][label]" placeholder="' +
			escapeHtml(labelText) +
			'"></label><span class="cf-subfield-row__control cf-subfield-key-display"><span>' +
			escapeHtml(keyText) +
			'</span><code>field</code></span><input type="hidden" class="cf-subfield-key-input" name="' +
			prefix +
			'[sub_fields][' +
			idx +
			'][key]" value=""><input type="hidden" class="cf-subfield-name-input" name="' +
			prefix +
			'[sub_fields][' +
			idx +
			'][name]" value=""><button type="button" class="button-link cf-subfield-remove" aria-label="' +
			escapeHtml(removeText) +
			'">&times;</button><div class="cf-subfield-row__details"><label class="cf-subfield-row__control cf-subfield-instructions"><span>Instructions</span><input type="text" name="' +
			prefix +
			'[sub_fields][' +
			idx +
			'][instructions]"></label><label class="cf-subfield-row__control cf-subfield-placeholder"><span>Placeholder</span><input type="text" name="' +
			prefix +
			'[sub_fields][' +
			idx +
			'][placeholder]"></label><label class="cf-subfield-row__control cf-subfield-default"><span>Default value</span><input type="text" name="' +
			prefix +
			'[sub_fields][' +
			idx +
			'][default]"></label><label class="cf-subfield-row__control cf-subfield-rows"><span>Rows</span><input type="number" min="1" max="30" name="' +
			prefix +
			'[sub_fields][' +
			idx +
			'][rows]" value="4"></label><label class="cf-subfield-row__control cf-subfield-new-lines"><span>New lines</span><select name="' +
			prefix +
			'[sub_fields][' +
			idx +
			'][new_lines]"><option value="">No formatting</option><option value="br">Convert to &lt;br&gt;</option><option value="wpautop">Convert to paragraphs</option></select></label><label class="cf-subfield-row__control cf-subfield-width"><span>Width</span><select name="' +
			prefix +
			'[sub_fields][' +
			idx +
			'][width]">' +
			widthOptionsHtml() +
			'</select></label><label class="cf-subfield-row__control cf-subfield-choices"><span>Choices</span><textarea rows="3" name="' +
			prefix +
			'[sub_fields][' +
			idx +
			'][choices]" placeholder="value : Label"></textarea></label><label class="cf-check-label cf-subfield-required"><input type="checkbox" name="' +
			prefix +
			'[sub_fields][' +
			idx +
			'][required]" value="1"> Required</label></div></div>'
		);
	}

	function refreshSubFieldTypeUI($row) {
		var type = String($row.find('select[name$="[type]"]').first().val() || 'text');
		var isDisplayOnly = displayOnlyTypes.indexOf(type) !== -1;
		$row.find('.cf-subfield-placeholder').prop('hidden', !typeSupports(type, 'placeholder'));
		$row.find('.cf-subfield-default').prop('hidden', !typeSupports(type, 'default'));
		$row.find('.cf-subfield-choices').prop('hidden', choiceTypes.indexOf(type) === -1);
		$row.find('.cf-subfield-rows').prop('hidden', !typeSupports(type, 'rows'));
		$row.find('.cf-subfield-new-lines').prop('hidden', !typeSupports(type, 'new_lines'));
		$row.find('.cf-subfield-required').prop('hidden', isDisplayOnly);
		$row.find('.cf-subfield-width').prop('hidden', isDisplayOnly);
	}

	function refreshAllSubFieldTypeUI() {
		$('.cf-subfield-row').each(function () {
			refreshSubFieldTypeUI($(this));
		});
	}

	function syncSubFieldKey($label) {
		var $row = $label.closest('.cf-subfield-row');
		var $key = $row.find('.cf-subfield-key-input');
		var $name = $row.find('.cf-subfield-name-input');
		if (!$key.length || $key.data('cfPersisted') || $key.attr('data-cf-persisted')) {
			return;
		}
		var key = slugify($label.val()) || 'field';
		$key.val(key).attr('value', key);
		$name.val(key).attr('value', key);
		$key.each(function () {
			this.value = key;
			this.setAttribute('value', key);
		});
		$name.each(function () {
			this.value = key;
			this.setAttribute('value', key);
		});
		$row.find('.cf-subfield-key-display code').text(key);
	}

	function syncAllSubFieldKeys() {
		$('.cf-subfield-row').each(function () {
			var $row = $(this);
			var $key = $row.find('.cf-subfield-key-input');
			var key = $key.val() || '';
			if (!key) {
				syncSubFieldKey($row.find('.cf-subfield-label-input'));
				key = $key.val() || '';
			}
			$row.find('.cf-subfield-name-input').val(key).attr('value', key);
			$key.attr('value', key);
			$key.each(function () {
				this.value = key;
				this.setAttribute('value', key);
			});
			$row.find('.cf-subfield-name-input').each(function () {
				this.value = key;
				this.setAttribute('value', key);
			});
			$row.find('.cf-subfield-key-display code').text(key || 'field');
		});
	}

	function syncLayoutKey($label) {
		var $row = $label.closest('.cf-layout-row');
		var $key = $row.find('.cf-layout-key-input');
		if (!$key.length || $key.data('manual')) {
			return;
		}
		$key.val(slugify($label.val()));
	}

	$(function () {
		computeNextIndex();
		computeNextLocRuleIndex();

		$('#cf-fields-list .cf-field-row').each(function () {
			var $row = $(this);
			refreshFieldTypeUI($row);
			ensureFieldStorageKey($row);
			updateFieldKey($row);
			ensureFieldStorageKey($row);
		});

		syncLocationState();
		syncPositionPicker();
		hardRestoreFieldStorageKeys();
		restoreAllPersistedFieldKeys();
		hardRestoreFieldStorageKeys();
		window.setTimeout(hardRestoreFieldStorageKeys, 100);
		window.setTimeout(restoreAllPersistedFieldKeys, 250);
		window.setTimeout(hardRestoreFieldStorageKeys, 500);
		window.setTimeout(restoreAllPersistedFieldKeys, 1000);
		window.setTimeout(hardRestoreFieldStorageKeys, 1500);

		var $lastFieldTypeTrigger = $('#cf-add-field');

		function closeFieldTypeMenu(restoreFocus) {
			var $menu = $('#cf-field-type-menu');
			$menu.prop('hidden', true);
			$('.cf-open-field-type-menu').attr('aria-expanded', 'false');
			if (restoreFocus && $lastFieldTypeTrigger.length) {
				$lastFieldTypeTrigger.trigger('focus');
			}
		}

		$(document).on('click', '.cf-open-field-type-menu', function (e) {
			e.preventDefault();
			var $button = $(this);
			var $menu = $('#cf-field-type-menu');
			var isOpen = !$menu.prop('hidden');
			$lastFieldTypeTrigger = $button;
			$menu.prop('hidden', isOpen);
			$('.cf-open-field-type-menu').attr('aria-expanded', isOpen ? 'false' : 'true');
			if (!isOpen) {
				$menu.trigger('focus');
			}
		});

		$(document).on('click', '.cf-quick-add-btn', function (e) {
			e.preventDefault();
			addField($(this).data('cfAddType'));
			closeFieldTypeMenu(false);
		});

		$(document).on('click', '.cf-field-type-menu__close', function (e) {
			e.preventDefault();
			closeFieldTypeMenu(true);
		});

		$(document).on('click', function (e) {
			if ($(e.target).closest('#cf-field-type-menu, .cf-open-field-type-menu').length) {
				return;
			}

			closeFieldTypeMenu(false);
		});

		$(document).on('keydown', function (e) {
			if (e.key !== 'Escape') {
				return;
			}

			closeFieldTypeMenu(true);
		});

		function toggleFieldRow($row) {
			$row.toggleClass('collapsed');
			var expanded = !$row.hasClass('collapsed');
			$row.find('.cf-field-row__toggle').attr('aria-expanded', expanded ? 'true' : 'false');
		}

		$(document).on('click', '.cf-field-row__toggle', function (e) {
			e.preventDefault();
			e.stopPropagation();
			toggleFieldRow($(this).closest('.cf-field-row'));
		});

		$(document).on('click', '.cf-field-row__head', function (e) {
			if (!$(e.target).closest('.cf-field-row__handle, .cf-field-row__actions, .cf-field-row__duplicate, .cf-field-row__remove').length) {
				toggleFieldRow($(this).closest('.cf-field-row'));
			}
		});

		$(document).on('click', '.cf-field-editor-tab', function (e) {
			e.preventDefault();
			var $tab = $(this);
			var target = String($tab.data('cfFieldTab') || 'basic');
			var $row = $tab.closest('.cf-field-row');

			$row.find('.cf-field-editor-tab')
				.removeClass('is-active')
				.attr('aria-selected', 'false');
			$tab.addClass('is-active').attr('aria-selected', 'true');

			$row.find('.cf-field-editor-panel').each(function () {
				var match = String($(this).data('cfFieldPanel') || '') === target;
				$(this).toggleClass('is-active', match).prop('hidden', !match);
			});
		});

		$('#cf-import-toggle').on('click', function (e) {
			e.preventDefault();
			$('#cf-import-panel').prop('hidden', function (_i, hidden) {
				return !hidden;
			});
		});

		$(document).on('click', '.cf-field-row__duplicate', function (e) {
			e.preventDefault();
			e.stopPropagation();
			var $source = $(this).closest('.cf-field-row');
			computeNextIndex();
			var $clone = $source.clone();
			reindexFieldRow($clone, nextIndex);
			setControlValue($clone.find('.cf-field-key-input'), '');
			$clone.find('.cf-field-key-input')
				.removeData('manual')
				.removeData('cfPersisted')
				.removeAttr('data-cf-persisted');
			$clone.find('.cf-field-key-readonly').remove();
			$clone.find('.cf-field-name-input').remove();
			if (!$clone.find('.cf-field-key-preview').length) {
				$clone.find('.cf-field-storage .cf-field-control__label').after(buildFieldKeyPreview());
			}
			var label = $clone.find('.cf-field-label-input').val();
			if (label) {
				setControlValue($clone.find('.cf-field-label-input'), label + ' (Copy)');
			}
			updateFieldKey($clone);
			// Cloned tooltip roots carry the init marker but not the listeners.
			$clone.find('[data-wpps-accordion-tooltip-init]').removeAttr('data-wpps-accordion-tooltip-init');
			$source.after($clone);
			refreshFieldTypeUI($clone);
			$clone.find('.cf-conditional-rule-row').each(function () {
				refreshConditionalValueControl($(this));
			});
			updateRowTitle($clone);
			initTooltips();
			refreshAllConditionalFieldSelects();
			refreshAllConditionalValueControls();
			if ($('#cf-fields-list').sortable('instance')) {
				$('#cf-fields-list').sortable('refresh');
			}
		});

		$(document).on('click', '.cf-field-row__remove', function (e) {
			e.preventDefault();
			e.stopPropagation();
			if (!window.confirm(strings.confirmRemove || 'Remove this field?')) {
				return;
			}
			$(this).closest('.cf-field-row').remove();
			if (!$('#cf-fields-list .cf-field-row').length) {
				$('#cf-fields-list').empty().append(buildFieldsEmptyState());
			}
			refreshAllConditionalFieldSelects();
			refreshAllConditionalValueControls();
		});

		$(document).on('change', '.cf-field-type-input', function () {
			refreshFieldTypeUI($(this).closest('.cf-field-row'));
			refreshAllConditionalFieldSelects();
			refreshAllConditionalValueControls();
		});

		$(document).on('change', 'select[name$="[wysiwyg_tabs]"]', function () {
			syncWysiwygOptions($(this).closest('.cf-field-row'));
		});

		$(document).on('change', '.cf-field-allow-custom-input', function () {
			refreshFieldTypeUI($(this).closest('.cf-field-row'));
		});

		$(document).on('change', '.cf-field-select-ui-input, .cf-field-select-create-input', function () {
			refreshFieldTypeUI($(this).closest('.cf-field-row'));
		});

		$(document).on('change', '.cf-field-multiple input[type="checkbox"]', function () {
			var $row = $(this).closest('.cf-field-row');
			syncDefaultValueControl($row, $row.find('.cf-field-type-input').val());
			refreshFieldGridSpans($row);
		});

		$(document).on('change', '.cf-field-toggle-ui-input', function () {
			refreshFieldTypeUI($(this).closest('.cf-field-row'));
		});

		$(document).on('change', 'select[name$="[taxonomy_field_type]"]', function () {
			refreshFieldTypeUI($(this).closest('.cf-field-row'));
		});

		$(document).on('input', '.cf-field-label-input', function () {
			var $row = $(this).closest('.cf-field-row');
			var oldKey = fieldRowGeneratedKey($row);
			updateRowTitle($row);
			updateFieldKey($row);
			rewriteConditionalSourceKey(oldKey, fieldRowGeneratedKey($row));
			refreshAllConditionalFieldSelects();
			refreshAllConditionalValueControls();
		});

		$('#cf-loc-screen').on('change', syncLocationState);
		$(document).on('change', '.cf-position-option input[type="radio"]', syncPositionPicker);

		$('#cf-location-rules-list .cf-rule-row').each(function () {
			syncRuleOperatorControl($(this));
			syncRuleValueControl($(this));
		});

		$(document).on('change', '.cf-rule-param', function () {
			var $row = $(this).closest('.cf-rule-row');
			if ($row.length) {
				syncRuleOperatorControl($row);
				syncRuleValueControl($row);
			}
		});

		$(document).on('change', '.cf-rule-operator', function () {
			var $row = $(this).closest('.cf-rule-row');
			if ($row.length) {
				syncRuleValueControl($row);
			}
		});

		$(document).on('click', '#cf-add-location-rule, .cf-add-location-rule', function (e) {
			e.preventDefault();
			var locTpl = document.getElementById('cf-location-rule-template');
			var template = locTpl ? (locTpl.innerHTML || '') : '';
			var maxRules = configuredLimit('maxLocationRules', 50);
			if (!template) {
				return;
			}
			if ($('#cf-location-rules-list .cf-rule-row').length >= maxRules) {
				showLimitMessage(strings.locationRuleLimitReached || 'This field group has reached the maximum number of location rules.');
				return;
			}
			computeNextLocRuleIndex();
			var html = template.replace(/__INDEX__/g, String(nextLocRuleIndex));
			$('#cf-location-rules-list .cf-rules-empty').remove();
			var $row = $(html.trim());
			$('#cf-location-rules-list').append($row);
			syncRuleOperatorControl($row);
			syncRuleValueControl($row);
		});

		$(document).on('click', '.cf-rule-remove', function (e) {
			e.preventDefault();
			$(this).closest('.cf-rule-row').remove();
			if (!$('#cf-location-rules-list .cf-rule-row').length) {
				$('#cf-location-rules-list').append('<p class="cf-rules-empty"></p>');
			}
		});

		$(document).on('change', '.cf-conditional-enable', function () {
			$(this).closest('.cf-field-conditional').find('.cf-conditional-panel').prop('hidden', !$(this).is(':checked'));
		});

		function buildConditionalRuleRow(prefix, idx, $currentRow) {
			var $row = $('<div class="cf-conditional-rule-row"></div>');

			var $field = $('<select>').attr('name', prefix + '[conditional][rules][' + idx + '][field]');
			refreshConditionalFieldSelect($field, $currentRow);

			var $op = $('<select>').attr('name', prefix + '[conditional][rules][' + idx + '][operator]');
			var ops = data.ruleOperators || { '==': '==', '!=': '!=' };
			Object.keys(ops).forEach(function (op) {
				$op.append($('<option>').val(op).text(ops[op]));
			});

			var valueName = prefix + '[conditional][rules][' + idx + '][value]';
			var $valueWrap = $('<span class="cf-conditional-value-wrap"></span>')
				.attr('data-cf-name', valueName)
				.attr('data-cf-selected', '')
				.append($('<input type="text" class="regular-text cf-conditional-value">').attr('name', valueName));
			var $remove = $('<button type="button" class="button-link cf-conditional-rule-remove"></button>')
				.attr('aria-label', strings.removeCondition || 'Remove condition')
				.html('&times;');

			$row.append($field, $op, $valueWrap, $remove);
			return $row;
		}

		$(document).on('click', '.cf-add-conditional-rule', function (e) {
			e.preventDefault();
			var $fieldRow = $(this).closest('.cf-field-row');
			var $rules = $(this).closest('.cf-conditional-panel').find('.cf-conditional-rules');
			var prefix = $fieldRow.find('.cf-field-type-input').attr('name').replace('[type]', '');
			var idx = $rules.find('.cf-conditional-rule-row').length;
			var maxRules = configuredLimit('maxConditionalRules', 50);
			if (idx >= maxRules) {
				showLimitMessage(strings.conditionalRuleLimitReached || 'This field has reached the maximum number of conditional rules.');
				return;
			}
			var $newRow = buildConditionalRuleRow(prefix, idx, $fieldRow);
			$rules.append($newRow);
			refreshConditionalValueControl($newRow);
		});

		$(document).on('click', '.cf-conditional-rule-remove', function (e) {
			e.preventDefault();
			$(this).closest('.cf-conditional-rule-row').remove();
		});

		// Rebuild the value control when the trigger field or operator changes.
		$(document).on('change', '.cf-conditional-rule-row select[name$="[field]"], .cf-conditional-rule-row select[name$="[operator]"]', function () {
			refreshConditionalValueControl($(this).closest('.cf-conditional-rule-row'));
		});

		// When a trigger field's choices change, refresh dependent value dropdowns.
		$(document).on('input change', '#cf-fields-list textarea[name$="[choices]"]', function () {
			refreshAllConditionalValueControls();
		});

		refreshAllConditionalFieldSelects();
		refreshAllConditionalValueControls();

		$(document).on('click', '.cf-add-subfield', function (e) {
			e.preventDefault();
			var $list = $(this).closest('.cf-field-repeater').find('.cf-subfields-list');
			var prefix = $list.data('prefix');
			var idx = $list.find('.cf-subfield-row').length;
			var maxSubFields = configuredLimit('maxSubFields', 100);
			if (idx >= maxSubFields) {
				showLimitMessage(strings.subFieldLimitReached || 'This field has reached the maximum number of sub fields.');
				return;
			}
			$list.append(subFieldRowHtml(prefix, idx));
			var $newRow = $list.find('.cf-subfield-row').last();
			refreshSubFieldTypeUI($newRow);
			$newRow.find('.cf-subfield-label-input').trigger('focus');
		});

		$(document).on('click', '.cf-add-layout-subfield', function (e) {
			e.preventDefault();
			var $list = $(this).closest('.cf-layout-row__fields').find('.cf-layout-subfields-list');
			var prefix = $list.data('prefix');
			var idx = $list.find('.cf-subfield-row').length;
			var maxSubFields = configuredLimit('maxSubFields', 100);
			if (idx >= maxSubFields) {
				showLimitMessage(strings.subFieldLimitReached || 'This layout has reached the maximum number of sub fields.');
				return;
			}
			$list.append(subFieldRowHtml(prefix, idx));
			var $newRow = $list.find('.cf-subfield-row').last();
			refreshSubFieldTypeUI($newRow);
			$newRow.find('.cf-subfield-label-input').trigger('focus');
		});

		$(document).on('change', '.cf-subfield-row select[name$="[type]"]', function () {
			refreshSubFieldTypeUI($(this).closest('.cf-subfield-row'));
		});

		$(document).on('input', '.cf-subfield-label-input', function () {
			syncSubFieldKey($(this));
		});

		$(document).on('input', '.cf-layout-key-input', function () {
			$(this).data('manual', true);
		});

		$(document).on('input', '.cf-layout-label-input', function () {
			syncLayoutKey($(this));
		});

		refreshAllSubFieldTypeUI();

		repairSaveHiddenFields($('#cf-form'));

		function syncCloneSource($picker) {
			$picker
				.closest('.cf-field-clone')
				.find('.cf-clone-source-input')
				.val(($picker.val() || []).join(','));
		}

		$(document).on('change input', '.cf-clone-source-picker', function () {
			syncCloneSource($(this));
		});

		$(document).on('submit', '#cf-form', function () {
			repairSaveHiddenFields($(this));
			hardRestoreFieldStorageKeys();
			$('#cf-fields-list .cf-field-row').each(function () {
				var $row = $(this);
				restorePersistedFieldKey($row);
				ensureFieldStorageKey($row);
				updateFieldKey($row);
				ensureFieldStorageKey($row);
				syncFieldNameInput($row);
				syncHiddenSettingControls($row);
			});
			syncAllSubFieldKeys();
			refreshAllConditionalFieldSelects();
			refreshAllConditionalValueControls();

			$(this).find('.cf-clone-source-picker').each(function () {
				syncCloneSource($(this));
			});
		});

		$(document).on('click', '.cf-subfield-remove', function (e) {
			e.preventDefault();
			$(this).closest('.cf-subfield-row').remove();
		});

		$(document).on('click', '.cf-add-layout', function (e) {
			e.preventDefault();
			var $list = $(this).closest('.cf-field-flexible').find('.cf-layouts-list');
			var prefix = $list.data('prefix');
			var idx = $list.find('.cf-layout-row').length;
			var maxLayouts = configuredLimit('maxLayouts', 50);
			if (idx >= maxLayouts) {
				showLimitMessage(strings.layoutLimitReached || 'This flexible content field has reached the maximum number of layouts.');
				return;
			}
			$list.append(
				'<div class="cf-layout-row" data-index="' +
					idx +
					'"><div class="cf-layout-row__head"><label class="cf-layout-row__control"><span>' +
					escapeHtml(strings.layoutLabel || 'Layout label') +
					'</span><input type="text" class="cf-layout-label-input" name="' +
					prefix +
					'[layouts][' +
					idx +
					'][label]" placeholder="' +
					escapeHtml(strings.layoutLabel || 'Layout label') +
					'"></label><label class="cf-layout-row__control"><span>' +
					escapeHtml(strings.layoutKey || 'Layout key') +
					'</span><input type="text" class="cf-layout-key-input" name="' +
					prefix +
					'[layouts][' +
					idx +
					'][key]" placeholder="' +
					escapeHtml(strings.layoutKey || 'Layout key') +
					'"></label><label class="cf-layout-row__control"><span>Display</span><select name="' +
					prefix +
					'[layouts][' +
					idx +
					'][display]"><option value="block">Block</option><option value="table">Table</option><option value="row">Row</option></select></label><label class="cf-layout-row__control"><span>Min</span><input type="number" class="small-text" name="' +
					prefix +
					'[layouts][' +
					idx +
					'][min]" value="0" min="0"></label><label class="cf-layout-row__control"><span>Max</span><input type="number" class="small-text" name="' +
					prefix +
					'[layouts][' +
					idx +
					'][max]" value="0" min="0"></label><button type="button" class="button-link cf-layout-remove" aria-label="' +
					escapeHtml(strings.removeLayout || 'Remove layout') +
					'">&times;</button></div><div class="cf-layout-row__fields"><span class="cf-field-control__label">' +
					escapeHtml(strings.layoutSubFields || 'Layout sub fields') +
					'</span><div class="cf-subfields-list cf-layout-subfields-list" data-prefix="' +
					prefix +
					'[layouts][' +
					idx +
					']"></div><button type="button" class="button button-small cf-add-layout-subfield">' +
					escapeHtml(strings.addSubField || 'Add sub field') +
					'</button></div></div>'
			);
			$list.find('.cf-layout-row').last().find('.cf-layout-label-input').trigger('focus');
		});

		$(document).on('click', '.cf-layout-remove', function (e) {
			e.preventDefault();
			$(this).closest('.cf-layout-row').remove();
		});

		// Auto-generate the group key on new groups.
		var $groupKey = $('#cf-key');
		if ($groupKey.length && $groupKey.is('input')) {
			if (!$groupKey.val()) {
				$groupKey.val(generateGroupKey());
			}
			$groupKey.on('input', function () {
				$groupKey.data('manual', true);
			});
		}

		// Sortable field rows (matches Options Page Builder drag handle pattern).
		if (typeof $.fn.sortable === 'function') {
			$('#cf-fields-list').sortable({
				handle: '.cf-field-row__handle',
				items: '> .cf-field-row',
				placeholder: 'cf-field-row-placeholder',
				axis: 'y',
				tolerance: 'pointer',
			});
		}

		$(document).on('click', '.cf-delete', function (e) {
			if (!window.confirm(strings.confirmDelete || 'Delete this field group?')) {
				e.preventDefault();
			}
		});

		// Settings accordion tabs (Location / Presentation / Usage).
		$('.cf-settings-tab').on('click', function () {
			var target = $(this).data('tab');

			$('.cf-settings-tab')
				.removeClass('is-active')
				.attr('aria-selected', 'false');
			$(this).addClass('is-active').attr('aria-selected', 'true');

			$('.cf-settings-panel').each(function () {
				var match = this.id === 'cf-settings-tab-' + target;
				$(this).toggleClass('is-active', match).prop('hidden', !match);
			});
		});

		$(document).on('click', '.cf-usage-copy', function (e) {
			e.preventDefault();
			var $btn = $(this);
			var text = String($btn.data('copy') || '').trim();
			if (!text) {
				return;
			}

			function markCopied() {
				var original = $btn.data('cfCopyLabel');
				if (original === undefined) {
					$btn.data('cfCopyLabel', $.trim($btn.text()));
				}
				$btn.addClass('is-copied');
				if ($btn.find('.dashicons').length) {
					$btn.contents().filter(function () {
						return this.nodeType === 3;
					}).remove();
					$btn.append(document.createTextNode(' ' + (strings.copied || 'Copied')));
				} else {
					$btn.text(strings.copied || 'Copied');
				}
				window.setTimeout(function () {
					$btn.removeClass('is-copied');
					if ($btn.find('.dashicons').length) {
						$btn.contents().filter(function () {
							return this.nodeType === 3;
						}).remove();
						$btn.append(document.createTextNode(' ' + (strings.copy || 'Copy')));
					} else {
						$btn.text(original || strings.copy || 'Copy');
					}
				}, 1600);
			}

			if (navigator.clipboard && navigator.clipboard.writeText) {
				navigator.clipboard.writeText(text).then(markCopied);
				return;
			}

			var $temp = $('<textarea>').val(text).css({ position: 'fixed', left: '-9999px' }).appendTo('body');
			$temp[0].select();
			try {
				document.execCommand('copy');
				markCopied();
			} catch (err) {
			}
			$temp.remove();
		});

	});

	document.addEventListener('submit', function (event) {
		if (event.target && event.target.id === 'cf-form') {
			hardRestoreFieldStorageKeys();
		}
	}, true);
})(jQuery);
