/**
* Accepta Repeater Control JavaScript
* Handles the interactive functionality for the repeater control
*/
(function($) {
'use strict';
function initializeRepeaterControl($control, controlId) {
// Prevent double initialization
if ($control.data('initialized')) {
return;
}
$control.data('initialized', true);
var $input = $control.find('.accepta-repeater-input');
var $itemsContainer = $control.find('.accepta-repeater-items');
var $addButton = $control.find('.accepta-repeater-add-item');
var maxItems = parseInt($control.data('max-items')) || 10;
// Remove any existing event handlers to prevent duplicates
$addButton.off('click.accepta-repeater');
$itemsContainer.off('click.accepta-repeater');
// Add new item
$addButton.on('click.accepta-repeater', function(e) {
e.preventDefault();
e.stopPropagation();
var currentItems = $itemsContainer.find('.accepta-repeater-item').length;
if (currentItems >= maxItems) {
alert(acceptaRepeaterL10n.maxItems);
return;
}
addNewItem($control, controlId);
});
// Handle item actions (delete, toggle) with namespaced events
$itemsContainer.on('click.accepta-repeater', '.accepta-repeater-item-delete', function(e) {
e.preventDefault();
e.stopPropagation();
if (confirm('Are you sure you want to delete this item?')) {
$(this).closest('.accepta-repeater-item').remove();
updateControlValue($control);
updateItemIndices($itemsContainer);
}
});
$itemsContainer.on('click.accepta-repeater', '.accepta-repeater-item-toggle', function(e) {
e.preventDefault();
e.stopPropagation();
var $item = $(this).closest('.accepta-repeater-item');
toggleRepeaterItem($item);
});
// Make the entire header clickable (except for action buttons)
$itemsContainer.on('click.accepta-repeater', '.accepta-repeater-item-header', function(e) {
// Don't toggle if clicking on action buttons
if ($(e.target).closest('.accepta-repeater-item-actions').length) {
return;
}
e.preventDefault();
e.stopPropagation();
var $item = $(this).closest('.accepta-repeater-item');
toggleRepeaterItem($item);
});
// Handle field changes with namespaced events
$itemsContainer.off('input.accepta-repeater change.accepta-repeater');
$itemsContainer.on('input.accepta-repeater change.accepta-repeater', '.accepta-repeater-field-input', function() {
updateControlValue($control);
updateItemTitle($(this));
});
// Handle media selection
$itemsContainer.on('click.accepta-repeater', '.accepta-repeater-media-select', function(e) {
e.preventDefault();
e.stopPropagation();
var $button = $(this);
var $field = $button.closest('.accepta-repeater-media-field');
var $input = $field.find('.accepta-repeater-media-input');
var $preview = $field.find('.accepta-repeater-media-preview');
var $removeButton = $field.find('.accepta-repeater-media-remove');
// Open WordPress media library
var mediaUploader = wp.media({
title: 'Select Image',
button: {
text: 'Use This Image'
},
multiple: false,
library: {
type: 'image'
}
});
mediaUploader.on('select', function() {
var attachment = mediaUploader.state().get('selection').first().toJSON();
var imageUrl = attachment.sizes && attachment.sizes.thumbnail ?
attachment.sizes.thumbnail.url : attachment.url;
$input.val(attachment.url).trigger('change');
$preview.html('');
$removeButton.show();
});
mediaUploader.open();
});
// Handle media removal
$itemsContainer.on('click.accepta-repeater', '.accepta-repeater-media-remove', function(e) {
e.preventDefault();
e.stopPropagation();
var $button = $(this);
var $field = $button.closest('.accepta-repeater-media-field');
var $input = $field.find('.accepta-repeater-media-input');
var $preview = $field.find('.accepta-repeater-media-preview');
$input.val('').trigger('change');
$preview.empty();
$button.hide();
});
// Handle Font Awesome icon selection
$itemsContainer.on('click.accepta-repeater', '.accepta-repeater-fontawesome-select', function(e) {
e.preventDefault();
e.stopPropagation();
var $button = $(this);
var $field = $button.closest('.accepta-repeater-fontawesome-field');
var $input = $field.find('.accepta-repeater-fontawesome-input');
var $preview = $field.find('.accepta-repeater-fontawesome-preview');
var $removeButton = $field.find('.accepta-repeater-fontawesome-remove');
openFontAwesomeModal(function(selectedIcon) {
$input.val(selectedIcon).trigger('change');
$preview.html('');
$removeButton.show();
updateControlValue($control);
});
});
// Handle Font Awesome icon removal
$itemsContainer.on('click.accepta-repeater', '.accepta-repeater-fontawesome-remove', function(e) {
e.preventDefault();
e.stopPropagation();
var $button = $(this);
var $field = $button.closest('.accepta-repeater-fontawesome-field');
var $input = $field.find('.accepta-repeater-fontawesome-input');
var $preview = $field.find('.accepta-repeater-fontawesome-preview');
$input.val('').trigger('change');
$preview.empty();
$button.hide();
updateControlValue($control);
});
// Handle icon type change for conditional field display
$itemsContainer.on('change.accepta-repeater', '[data-field="icon_type"]', function() {
var $select = $(this);
var $item = $select.closest('.accepta-repeater-item');
var iconType = $select.val();
// Show/hide fields based on icon type
var $iconField = $item.find('[data-field="icon"]').closest('.accepta-repeater-field');
var $customIconField = $item.find('[data-field="custom_icon"]').closest('.accepta-repeater-field');
if (iconType === 'fontawesome') {
$iconField.show().addClass('show');
$customIconField.hide().removeClass('show');
} else if (iconType === 'custom') {
$iconField.hide().removeClass('show');
$customIconField.show().addClass('show');
}
updateControlValue($control);
});
// Initialize existing items
$itemsContainer.find('.accepta-repeater-item').each(function(index) {
$(this).attr('data-index', index);
});
// Make items sortable
$itemsContainer.sortable({
handle: '.accepta-repeater-item-header',
axis: 'y',
placeholder: 'accepta-repeater-item-placeholder',
helper: 'clone',
opacity: 0.8,
cursor: 'move',
tolerance: 'pointer',
start: function(event, ui) {
ui.placeholder.height(ui.item.height());
ui.helper.addClass('accepta-repeater-item-dragging');
},
stop: function(event, ui) {
ui.item.removeClass('accepta-repeater-item-dragging');
updateControlValue($control);
updateItemIndices($itemsContainer);
}
});
}
function addNewItem($control, controlId) {
var $itemsContainer = $control.find('.accepta-repeater-items');
var newIndex = $itemsContainer.find('.accepta-repeater-item').length;
var template = $('#tmpl-accepta-repeater-item-' + controlId).html();
if (!template) {
console.error('Template not found for control: ' + controlId);
return;
}
// Replace template variables
var itemHtml = template.replace(/\{\{data\.index\}\}/g, newIndex)
.replace(/\{\{data\.index \+ 1\}\}/g, newIndex + 1);
var $newItem = $(itemHtml);
$itemsContainer.append($newItem);
// Set up the new item state
var $content = $newItem.find('.accepta-repeater-item-content');
// Expand the new item (only new items should be expanded)
$content.show();
$newItem.addClass('expanded');
// Initialize conditional field display for new item
var $iconTypeSelect = $newItem.find('[data-field="icon_type"]');
if ($iconTypeSelect.length) {
// Set default value to fontawesome
$iconTypeSelect.val('fontawesome');
// Trigger change event to show/hide appropriate fields
$iconTypeSelect.trigger('change');
}
// Focus on first field
setTimeout(function() {
$newItem.find('.accepta-repeater-field-input').first().focus();
}, 100);
updateControlValue($control);
}
function toggleRepeaterItem($item) {
var $content = $item.find('.accepta-repeater-item-content');
// Check current state and toggle accordingly
if ($content.is(':visible')) {
$content.slideUp();
$item.removeClass('expanded');
} else {
$content.slideDown();
$item.addClass('expanded');
}
}
function updateControlValue($control) {
var $input = $control.find('.accepta-repeater-input');
var $items = $control.find('.accepta-repeater-item');
var data = [];
$items.each(function() {
var $item = $(this);
var itemData = {};
$item.find('.accepta-repeater-field-input').each(function() {
var $field = $(this);
var fieldName = $field.data('field');
var fieldValue = $field.val();
if (fieldName && fieldValue !== undefined) {
itemData[fieldName] = fieldValue;
}
});
// Only add item if it has some data
if (Object.keys(itemData).length > 0) {
data.push(itemData);
}
});
$input.val(JSON.stringify(data)).trigger('change');
}
function updateItemTitle($field) {
var $item = $field.closest('.accepta-repeater-item');
var $title = $item.find('.accepta-repeater-item-title');
var fieldName = $field.data('field');
var fieldValue = $field.val();
// Update title if this is a label field
if (fieldName === 'label' && fieldValue) {
$title.text(fieldValue);
} else if (fieldName === 'label' && !fieldValue) {
var index = $item.data('index');
$title.text('Item ' + (index + 1));
}
}
function updateItemIndices($container) {
$container.find('.accepta-repeater-item').each(function(index) {
var $item = $(this);
$item.attr('data-index', index);
// Update title if it's still default
var $title = $item.find('.accepta-repeater-item-title');
var titleText = $title.text();
if (titleText.match(/^Item \d+$/)) {
$title.text('Item ' + (index + 1));
}
});
}
// Add control to customizer control types
wp.customize.controlConstructor['accepta-repeater'] = wp.customize.Control.extend({
ready: function() {
var control = this;
var $control = this.container.find('.accepta-repeater-control');
// Initialize the control
initializeRepeaterControl($control, control.id);
// Ensure all existing items are closed by default
$control.find('.accepta-repeater-item').each(function(index) {
var $item = $(this);
var $content = $item.find('.accepta-repeater-item-content');
// Close all items by default
$content.hide();
$item.removeClass('expanded');
// Initialize conditional field display
var $iconTypeSelect = $item.find('[data-field="icon_type"]');
if ($iconTypeSelect.length) {
$iconTypeSelect.trigger('change');
}
});
}
});
// Font Awesome Modal Functions
var fontAwesomeIcons = null;
var currentFontAwesomeCallback = null;
function openFontAwesomeModal(callback) {
currentFontAwesomeCallback = callback;
if (!fontAwesomeIcons) {
loadFontAwesomeIcons();
}
createFontAwesomeModal();
$('.accepta-fontawesome-modal').show();
}
function loadFontAwesomeIcons() {
// For now, just render the icons directly without AJAX
// This prevents the wp.customize.settings.nonce error
renderFontAwesomeIcons();
}
function createFontAwesomeModal() {
if ($('.accepta-fontawesome-modal').length) {
return;
}
// Ensure Font Awesome is loaded
if (!$('link[href*="fontawesome"]').length && !$('link[href*="font-awesome"]').length) {
var templateUrl = (typeof acceptaRepeaterL10n !== 'undefined' && acceptaRepeaterL10n.templateUrl)
? acceptaRepeaterL10n.templateUrl
: '';
if (templateUrl) {
$('').appendTo('head');
}
}
var modalHtml = `