/**
* Console logging handler.
*
* @package contact-form-7-mailchimp-extension
* @author renzo.johnson@gmail.com
* @copyright 2014-2026 https://renzojohnson.com
* @license GPL-3.0+
*/
'use strict';
(function() {
if (typeof chimpmaticLite === 'undefined' || !chimpmaticLite.loggingEnabled) {
return;
}
const originalConsole = {
log: console.log,
info: console.info,
warn: console.warn,
error: console.error,
debug: console.debug
};
async function sendLogToServer(level, message, ...args) {
let formattedMessage = message;
let dataString = '';
if (args.length > 0) {
try {
dataString = args.map(arg => typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg)).join(' | ');
formattedMessage += ' ' + dataString;
} catch (e) {
dataString = '[Unable to stringify arguments]';
}
}
try {
await fetch(`${chimpmaticLite.restUrl}logs/browser`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': chimpmaticLite.restNonce
},
body: JSON.stringify({ level, message: formattedMessage, data: dataString })
});
} catch (error) {
originalConsole.error('[ChimpMatic Lite] Failed to send log to server:', error);
}
}
['log', 'info', 'warn', 'error', 'debug'].forEach(level => {
console[level] = function(...args) {
originalConsole[level].apply(console, args);
const message = args[0] ? String(args[0]) : '';
sendLogToServer(level, message, ...args.slice(1));
};
});
})();
document.addEventListener('DOMContentLoaded', function() {
if (typeof chimpmaticLite === 'undefined') {
return;
}
const isProFieldPanelActive = !!document.getElementById('chm_panel_gencamposygrupos');
let cachedLists = chimpmaticLite.lists && chimpmaticLite.lists.length > 0 ? chimpmaticLite.lists : [];
function getFormId() {
const dataContainer = document.getElementById('cmatic_data');
return dataContainer?.dataset?.formId ? parseInt(dataContainer.dataset.formId, 10) || 0 : 0;
}
async function fetchMailchimpLists(formId, apiKey) {
const response = await fetch(`${chimpmaticLite.restUrl}lists`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': chimpmaticLite.restNonce
},
body: JSON.stringify({ form_id: formId, api_key: apiKey })
});
const data = await response.json();
if (!response.ok) throw new Error(data.message || 'Failed to fetch lists');
return data;
}
async function getDebugLog(filtered = true) {
const url = filtered
? `${chimpmaticLite.restUrl}logs`
: `${chimpmaticLite.restUrl}logs?filter=0`;
const response = await fetch(url, {
method: 'GET',
headers: { 'X-WP-Nonce': chimpmaticLite.restNonce }
});
const data = await response.json();
if (!response.ok) throw new Error(data.message || 'Failed to fetch log');
return data;
}
async function clearDebugLog() {
const response = await fetch(`${chimpmaticLite.restUrl}logs/clear`, {
method: 'POST',
headers: { 'X-WP-Nonce': chimpmaticLite.restNonce }
});
const data = await response.json();
if (!response.ok) throw new Error(data.message || 'Failed to clear log');
return data;
}
function findBestMatch(mergeTag, fieldName, cf7Tags) {
if (!mergeTag || !cf7Tags || cf7Tags.length === 0) return null;
const normalize = str => String(str).toLowerCase().replace(/[^a-z0-9]/g, '');
const normalizedTag = normalize(mergeTag);
const normalizedName = normalize(fieldName);
const keywordMappings = {
email: ['email', 'mail', 'correo'],
emailaddress: ['email', 'mail'],
fname: ['name', 'firstname', 'first', 'nombre', 'your-name'],
firstname: ['name', 'firstname', 'first', 'nombre'],
lname: ['lastname', 'last', 'apellido', 'surname'],
lastname: ['lastname', 'last', 'apellido'],
name: ['name', 'nombre', 'your-name'],
fullname: ['name', 'fullname', 'nombre'],
phone: ['phone', 'tel', 'telefono', 'mobile', 'cell'],
mobilephone: ['phone', 'tel', 'mobile', 'cell'],
address: ['address', 'direccion', 'street'],
address1: ['address', 'address1', 'street'],
address2: ['address2', 'apt', 'suite'],
city: ['city', 'ciudad'],
state: ['state', 'province', 'region', 'estado'],
zip: ['zip', 'postal', 'postcode'],
country: ['country', 'pais'],
company: ['company', 'organization', 'empresa', 'org'],
website: ['website', 'url', 'web', 'sitio'],
birthday: ['birthday', 'birth', 'dob', 'cumpleanos'],
message: ['message', 'comments', 'mensaje', 'nota', 'your-message']
};
for (const [mcKeyword, cf7Keywords] of Object.entries(keywordMappings)) {
if (normalizedTag.includes(mcKeyword) || normalizedName.includes(mcKeyword)) {
for (const cf7Keyword of cf7Keywords) {
const match = cf7Tags.find(tag => normalize(tag.name || tag).includes(cf7Keyword));
if (match) return match.name || match;
}
}
}
for (const tag of cf7Tags) {
const tagName = normalize(tag.name || tag);
if (normalizedTag.includes(tagName) || tagName.includes(normalizedTag)) return tag.name || tag;
if (normalizedName.includes(tagName) || tagName.includes(normalizedName)) return tag.name || tag;
}
return null;
}
function applyFuzzyMatching(mergeFields) {
const cf7Tags = [];
const sampleDropdown = document.getElementById('wpcf7-mailchimp-field4');
if (sampleDropdown) {
Array.from(sampleDropdown.options).forEach(option => {
if (option.value && option.value.trim() !== '' && option.value !== ' ') {
cf7Tags.push({ name: option.value });
}
});
}
if (cf7Tags.length === 0) return;
const fieldMappings = [
{ id: 'field3', index: 0 },
{ id: 'field4', index: 1 },
{ id: 'field5', index: 2 },
{ id: 'field6', index: 3 }
];
const changedFields = [];
fieldMappings.forEach(mapping => {
const mergeField = mergeFields[mapping.index];
if (!mergeField) return;
const dropdown = document.getElementById(`wpcf7-mailchimp-${mapping.id}`);
if (!dropdown) return;
if (dropdown.value && dropdown.value.trim() !== '' && dropdown.value !== ' ') return;
const bestMatch = findBestMatch(mergeField.tag, mergeField.name, cf7Tags);
if (bestMatch) {
dropdown.value = bestMatch;
changedFields.push({ field: mapping.id, value: bestMatch });
Array.from(dropdown.options).forEach(opt => {
opt.defaultSelected = (opt.value === bestMatch);
});
}
});
if (changedFields.length > 0) {
saveFieldMappings(changedFields);
}
}
async function saveFieldMappings(fields) {
const formId = getFormId();
if (!formId || fields.length === 0) return;
for (const { field, value } of fields) {
try {
await fetch(chimpmaticLite.restUrl + 'form/field', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': chimpmaticLite.restNonce
},
body: JSON.stringify({ form_id: formId, field, value })
});
} catch (error) {
console.error('Failed to save field mapping:', field, error);
}
}
}
function updateFieldLabels(mergeFields) {
const fieldMappings = [
{ id: 'field3', index: 0 },
{ id: 'field4', index: 1 },
{ id: 'field5', index: 2 },
{ id: 'field6', index: 3 }
];
fieldMappings.forEach(mapping => {
const label = document.querySelector(`label[for="wpcf7-mailchimp-${mapping.id}"]`);
const container = label ? label.closest('.mcee-container') : null;
if (mergeFields[mapping.index]) {
const field = mergeFields[mapping.index];
if (label) {
const requiredBadge = field.tag === 'EMAIL' ? 'Required' : '';
label.innerHTML = `${field.name} - *|${field.tag}|* ${field.type} ${requiredBadge}`;
}
if (container) container.style.display = '';
} else {
if (container) container.style.display = 'none';
}
});
applyFuzzyMatching(mergeFields);
}
function updateFieldsNotice(totalMergeFields, liteLimit, audienceName) {
const notice = document.getElementById('cmatic-fields-notice');
if (!notice) return;
const noticeText = notice.querySelector('.cmatic-notice');
if (totalMergeFields > liteLimit) {
if (noticeText) {
const docsLink = notice.querySelector('a');
const linkHtml = docsLink ? ' ' + docsLink.outerHTML : '';
const name = audienceName ? '' + audienceName + ' ' : '';
noticeText.innerHTML = 'Your ' + name + 'audience has ' + totalMergeFields + ' merge fields. Chimpmatic Lite supports up to ' + liteLimit + ' field mappings.' + linkHtml;
}
notice.classList.remove('cmatic-hidden');
notice.classList.add('cmatic-visible');
} else {
notice.classList.remove('cmatic-visible');
notice.classList.add('cmatic-hidden');
}
}
function renderListsDropdown(listsData, currentSelection) {
const { api_valid, lists, total } = listsData;
if (lists && lists.length > 0) {
cachedLists = lists;
}
const dataContainer = document.getElementById('cmatic_data');
if (dataContainer) dataContainer.dataset.apiValid = api_valid ? '1' : '0';
const label = document.getElementById('cmatic-audiences-label');
if (label) {
label.textContent = api_valid && total > 0 ? `Total Mailchimp Audiences: ${total}` : 'Mailchimp Audiences';
}
let optionsHtml = '';
let selectedAudience = '';
if (api_valid && total > 0) {
selectedAudience = currentSelection;
if (!selectedAudience && lists.length > 0) selectedAudience = lists[0].id;
lists.forEach((list, index) => {
const selected = selectedAudience === list.id ? ' selected' : '';
const optionText = `${index + 1}:${list.member_count} ${list.name} ${list.field_count} fields #${list.id}`;
optionsHtml += ``;
});
const selectedList = lists.find(l => l.id === selectedAudience) || lists[0];
updateFieldsNotice(selectedList.field_count, chimpmaticLite.liteFieldsLimit || 4, selectedList.name);
}
return optionsHtml;
}
function updateApiStatus(isValid) {
// Update sidebar status
const versionInfo = document.getElementById('chimpmatic-version-info');
if (versionInfo) {
const statusText = versionInfo.querySelector('.chmm');
if (statusText) {
if (isValid) {
statusText.classList.remove('invalid');
statusText.classList.add('valid');
statusText.textContent = 'API Connected';
} else {
statusText.classList.remove('valid');
statusText.classList.add('invalid');
statusText.textContent = 'API Inactive';
}
}
}
// Update header status dot
const headerDot = document.querySelector('.cmatic-header__status-dot');
const headerText = document.querySelector('.cmatic-header__status-text');
if (headerDot) {
if (isValid) {
headerDot.classList.remove('cmatic-header__status-dot--disconnected');
headerDot.classList.add('cmatic-header__status-dot--connected');
} else {
headerDot.classList.remove('cmatic-header__status-dot--connected');
headerDot.classList.add('cmatic-header__status-dot--disconnected');
}
}
if (headerText) {
headerText.textContent = isValid ? 'API Connected' : 'API Inactive';
}
}
function updateLiteBadgeStatus(status) {
const liteBadge = document.querySelector('.cm-lite');
if (!liteBadge) return;
liteBadge.classList.remove('cm-status-neutral', 'cm-status-connected', 'cm-status-error');
if (status === 'connected') liteBadge.classList.add('cm-status-connected');
else if (status === 'error') liteBadge.classList.add('cm-status-error');
else liteBadge.classList.add('cm-status-neutral');
}
async function getSecureApiKey(apiKeyInput, formId) {
const isMasked = apiKeyInput.dataset.isMasked === '1';
const hasKey = apiKeyInput.dataset.hasKey === '1';
const inputValue = apiKeyInput.value.trim();
if (!isMasked) {
return inputValue;
}
if (!hasKey) {
return '';
}
try {
const response = await fetch(
`${chimpmaticLite.restUrl}api-key/${formId}`,
{
method: 'GET',
headers: {
'X-WP-Nonce': chimpmaticLite.restNonce,
'Content-Type': 'application/json'
}
}
);
if (!response.ok) {
console.error('ChimpMatic: Failed to fetch API key');
return '';
}
const data = await response.json();
return data.api_key || '';
} catch (err) {
console.error('ChimpMatic: Error fetching API key', err);
return '';
}
}
const fetchListsButton = document.getElementById('chm_activalist');
if (fetchListsButton) {
fetchListsButton.addEventListener('click', async function(event) {
event.preventDefault();
const apiKeyInput = document.getElementById('cmatic-api');
const selectElement = document.getElementById('wpcf7-mailchimp-list');
if (!apiKeyInput || !selectElement) return;
const formId = getFormId();
const apiKey = await getSecureApiKey(apiKeyInput, formId);
if (!apiKey) {
if (typeof showInlineMessage === 'function') {
showInlineMessage(fetchListsButton, 'Enter API key first', 'warning');
}
updateApiStatus(false);
updateLiteBadgeStatus('neutral');
return;
}
if (!formId || formId <= 0) {
if (typeof showInlineMessage === 'function') {
showInlineMessage(fetchListsButton, 'Save form first', 'warning');
}
updateApiStatus(false);
updateLiteBadgeStatus('neutral');
return;
}
const originalText = fetchListsButton.value || fetchListsButton.textContent;
fetchListsButton.disabled = true;
if (fetchListsButton.tagName === 'INPUT') fetchListsButton.value = 'Syncing Audiences...';
else fetchListsButton.textContent = 'Syncing Audiences...';
try {
const data = await fetchMailchimpLists(formId, apiKey);
const currentSelection = selectElement.value || '';
selectElement.innerHTML = renderListsDropdown(data, currentSelection);
attachFetchFieldsListeners();
const newListDropdown = document.getElementById('wpcf7-mailchimp-list');
if (newListDropdown && newListDropdown.value) {
if (isProFieldPanelActive) {
newListDropdown.dispatchEvent(new Event('change', { bubbles: true }));
} else {
fetchFieldsForSelectedList();
}
}
if (data.api_valid) {
updateApiStatus(true);
updateLiteBadgeStatus('connected');
document.querySelectorAll('.chmp-inactive').forEach(el => {
el.classList.remove('chmp-inactive');
el.classList.add('chmp-active');
});
const newUserSection = document.getElementById('chmp-new-user');
if (newUserSection) {
newUserSection.classList.remove('chmp-active');
newUserSection.classList.add('chmp-inactive');
}
} else {
updateApiStatus(false);
updateLiteBadgeStatus('error');
document.querySelectorAll('.chmp-active').forEach(el => {
el.classList.remove('chmp-active');
el.classList.add('chmp-inactive');
});
const newUserSection = document.getElementById('chmp-new-user');
if (newUserSection) {
newUserSection.classList.remove('chmp-inactive');
newUserSection.classList.add('chmp-active');
}
}
if (fetchListsButton.tagName === 'INPUT') fetchListsButton.value = 'Synced ✓';
else fetchListsButton.textContent = 'Synced ✓';
setTimeout(() => {
if (fetchListsButton.tagName === 'INPUT') fetchListsButton.value = originalText;
else fetchListsButton.textContent = originalText;
fetchListsButton.disabled = false;
}, 1000);
} catch (error) {
if (fetchListsButton.tagName === 'INPUT') fetchListsButton.value = originalText;
else fetchListsButton.textContent = originalText;
fetchListsButton.disabled = false;
alert(chimpmaticLite.i18n.error);
}
});
}
const apiKeyInput = document.getElementById('cmatic-api');
if (apiKeyInput && fetchListsButton) {
function isValidApiKey(key) {
if (key.length !== 36 || key.charAt(32) !== '-') return false;
if (!/^[a-f0-9]{32}$/i.test(key.substring(0, 32))) return false;
const dc = key.substring(33).toLowerCase();
const validDCs = ['us1','us2','us3','us4','us5','us6','us7','us8','us9','us10','us11','us12','us13','us14','us15','us16','us17','us18','us19','us20','us21'];
return validDCs.includes(dc);
}
function debounce(func, wait) {
let timeout;
return function(...args) {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, args), wait);
};
}
apiKeyInput.addEventListener('paste', function() {
setTimeout(() => {
if (isValidApiKey(apiKeyInput.value.trim())) fetchListsButton.click();
}, 50);
});
apiKeyInput.addEventListener('input', function() {
updateLiteBadgeStatus('neutral');
});
apiKeyInput.addEventListener('input', debounce(function() {
const apiKey = apiKeyInput.value.trim();
if (isValidApiKey(apiKey)) {
fetchListsButton.click();
} else if (apiKey === '') {
const formId = getFormId();
if (formId) {
fetch(`${chimpmaticLite.restUrl}settings/reset`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': chimpmaticLite.restNonce
},
body: JSON.stringify({ form_id: formId })
})
.then(response => response.json())
.then(() => {
const selectElement = document.getElementById('wpcf7-mailchimp-list');
if (selectElement) selectElement.innerHTML = '';
const label = document.getElementById('cmatic-audiences-label');
if (label) label.textContent = 'Mailchimp Audiences';
const fieldsContainer = document.getElementById('cmatic-fields');
if (fieldsContainer) fieldsContainer.innerHTML = '';
updateLiteBadgeStatus('neutral');
document.querySelectorAll('.chmp-active').forEach(el => {
el.classList.remove('chmp-active');
el.classList.add('chmp-inactive');
});
const newUserSection = document.getElementById('chmp-new-user');
if (newUserSection) {
newUserSection.classList.remove('chmp-inactive');
newUserSection.classList.add('chmp-active');
}
});
}
}
}, 500));
}
function initToggleAutoSave() {
const globalFields = ['debug', 'backlink', 'auto_update', 'telemetry'];
const toggles = document.querySelectorAll('.cmatic-toggle input[data-field]');
if (toggles.length === 0) return;
toggles.forEach(function(toggle) {
toggle.addEventListener('change', async function() {
const field = this.dataset.field;
if (!globalFields.includes(field)) return;
const enabled = this.checked;
const wrapper = this.closest('.cmatic-toggle');
if (wrapper) wrapper.classList.add('is-saving');
try {
const response = await fetch(chimpmaticLite.restUrl + 'settings/toggle', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': chimpmaticLite.restNonce
},
body: JSON.stringify({ field, enabled })
});
const data = await response.json();
if (wrapper) wrapper.classList.remove('is-saving');
if (data.success) {
// Sync defaultChecked to prevent CF7 beforeunload warning
this.defaultChecked = this.checked;
} else {
this.checked = !enabled;
}
} catch (error) {
if (wrapper) wrapper.classList.remove('is-saving');
this.checked = !enabled;
}
});
});
}
initToggleAutoSave();
function initSelectAutoSave() {
const selects = document.querySelectorAll('select.chm-select[data-field]');
if (selects.length === 0) return;
const perFormFields = ['double_optin', 'sync_tags'];
selects.forEach(function(select) {
select.addEventListener('change', async function() {
const field = this.dataset.field;
const value = this.value === '1';
const wrapper = this.closest('.mcee-container');
if (wrapper) wrapper.classList.add('is-saving');
try {
let url, body;
if (perFormFields.includes(field)) {
const formId = getFormId();
if (!formId) {
if (wrapper) wrapper.classList.remove('is-saving');
this.value = value ? '0' : '1';
return;
}
const rootUrl = chimpmaticLite.restUrl.replace('chimpmatic-lite/v1/', '');
url = rootUrl + 'cmatic/form/setting';
body = JSON.stringify({ form_id: formId, field, value });
} else {
url = chimpmaticLite.restUrl + 'settings/toggle';
body = JSON.stringify({ field, enabled: value });
}
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': chimpmaticLite.restNonce
},
body
});
const data = await response.json();
if (wrapper) wrapper.classList.remove('is-saving');
if (data.success) {
// Sync defaultSelected to prevent CF7 beforeunload warning
Array.from(this.options).forEach(function(opt) {
opt.defaultSelected = opt.selected;
});
} else {
this.value = value ? '0' : '1';
}
} catch (error) {
if (wrapper) wrapper.classList.remove('is-saving');
this.value = value ? '0' : '1';
}
});
});
}
initSelectAutoSave();
const debugLogButton = document.querySelector('.cme-trigger-log:not(.cmatic-accordion-btn)');
if (debugLogButton) {
debugLogButton.addEventListener('click', async function(event) {
event.preventDefault();
const logPanelContainer = document.getElementById('eventlog-sys');
const logPanel = document.getElementById('log_panel');
const advancedSettings = document.querySelector('.vc-advanced-settings');
const advancedToggleButton = document.querySelector('.vc-view-advanced');
const testContainer = document.getElementById('cmatic-test-container');
const testSubmissionBtn = document.querySelector('.vc-test-submission');
if (!logPanelContainer || !logPanel) return;
const isLogVisible = window.getComputedStyle(logPanelContainer).display !== 'none';
if (isLogVisible) {
logPanelContainer.style.transition = 'opacity 0.5s ease-out';
logPanelContainer.style.opacity = '0';
setTimeout(() => {
logPanelContainer.style.display = 'none';
logPanelContainer.style.removeProperty('opacity');
logPanelContainer.style.removeProperty('transition');
}, 500);
this.setAttribute('aria-expanded', 'false');
} else {
if (advancedSettings) {
const isAdvancedVisible = window.getComputedStyle(advancedSettings).display !== 'none';
if (isAdvancedVisible) {
advancedSettings.style.transition = 'opacity 0.5s ease-out';
advancedSettings.style.opacity = '0';
setTimeout(() => {
advancedSettings.style.display = 'none';
advancedSettings.style.removeProperty('opacity');
advancedSettings.style.removeProperty('transition');
}, 500);
if (advancedToggleButton) advancedToggleButton.setAttribute('aria-expanded', 'false');
}
}
if (testContainer) {
const isTestVisible = window.getComputedStyle(testContainer).display !== 'none';
if (isTestVisible) {
testContainer.style.transition = 'opacity 0.5s ease-out';
testContainer.style.opacity = '0';
setTimeout(() => {
testContainer.style.display = 'none';
testContainer.style.removeProperty('opacity');
testContainer.style.removeProperty('transition');
}, 500);
if (testSubmissionBtn) testSubmissionBtn.setAttribute('aria-expanded', 'false');
}
}
logPanel.textContent = chimpmaticLite.i18n.loading;
logPanelContainer.style.opacity = '0';
logPanelContainer.style.display = 'block';
logPanelContainer.style.transition = 'opacity 0.5s ease-in';
setTimeout(() => { logPanelContainer.style.opacity = '1'; }, 50);
this.setAttribute('aria-expanded', 'true');
try {
const data = await getDebugLog();
logPanel.textContent = data.success ? (data.logs || data.message) : 'Error: ' + (data.message || 'Unknown error');
} catch (error) {
logPanel.textContent = chimpmaticLite.i18n.error;
}
}
});
}
const advancedToggleButton = document.querySelector('.vc-view-advanced:not(.cmatic-accordion-btn)');
if (advancedToggleButton) {
advancedToggleButton.addEventListener('click', function(event) {
event.preventDefault();
const advancedSettings = document.querySelector('.vc-advanced-settings');
const logPanelContainer = document.getElementById('eventlog-sys');
const debugLogBtn = document.querySelector('.cme-trigger-log');
const testContainer = document.getElementById('cmatic-test-container');
const testSubmissionBtn = document.querySelector('.vc-test-submission');
if (!advancedSettings) return;
const isVisible = window.getComputedStyle(advancedSettings).display !== 'none';
if (isVisible) {
advancedSettings.style.transition = 'opacity 0.5s ease-out';
advancedSettings.style.opacity = '0';
setTimeout(() => {
advancedSettings.style.display = 'none';
advancedSettings.style.removeProperty('opacity');
advancedSettings.style.removeProperty('transition');
}, 500);
this.setAttribute('aria-expanded', 'false');
} else {
if (logPanelContainer) {
const isLogVisible = window.getComputedStyle(logPanelContainer).display !== 'none';
if (isLogVisible) {
logPanelContainer.style.transition = 'opacity 0.5s ease-out';
logPanelContainer.style.opacity = '0';
setTimeout(() => {
logPanelContainer.style.display = 'none';
logPanelContainer.style.removeProperty('opacity');
logPanelContainer.style.removeProperty('transition');
}, 500);
if (debugLogBtn) debugLogBtn.setAttribute('aria-expanded', 'false');
}
}
if (testContainer) {
const isTestVisible = window.getComputedStyle(testContainer).display !== 'none';
if (isTestVisible) {
testContainer.style.transition = 'opacity 0.5s ease-out';
testContainer.style.opacity = '0';
setTimeout(() => {
testContainer.style.display = 'none';
testContainer.style.removeProperty('opacity');
testContainer.style.removeProperty('transition');
}, 500);
if (testSubmissionBtn) testSubmissionBtn.setAttribute('aria-expanded', 'false');
}
}
advancedSettings.style.opacity = '0';
advancedSettings.style.display = 'block';
advancedSettings.style.transition = 'opacity 0.5s ease-in';
setTimeout(() => { advancedSettings.style.opacity = '1'; }, 50);
this.setAttribute('aria-expanded', 'true');
}
});
}
const clearLogsButton = document.querySelector('.vc-clear-logs');
if (clearLogsButton) {
clearLogsButton.addEventListener('click', async function(event) {
event.preventDefault();
const logPanel = document.getElementById('log_panel');
const originalText = this.textContent;
this.disabled = true;
this.textContent = 'Clearing Logs...';
try {
const data = await clearDebugLog();
if (data.success && data.cleared) {
this.textContent = 'Cleared';
if (logPanel) logPanel.textContent = 'Debug log cleared.';
} else {
this.textContent = 'Cleared';
if (logPanel) logPanel.textContent = data.message || 'Debug log was already empty.';
}
setTimeout(() => {
this.textContent = 'Clear Logs';
this.disabled = false;
}, 2000);
} catch (error) {
this.textContent = 'Clearing Log Error';
setTimeout(() => {
this.textContent = 'Clear Logs';
this.disabled = false;
}, 3000);
}
});
}
(function initAccordionPanels() {
const accordionContainer = document.querySelector('.cmatic-panel-toggles');
if (!accordionContainer) return;
const panelConfig = {
'eventlog-sys': {
filtered: true,
onOpen: async function(panel) {
const logPanel = document.getElementById('log_panel');
const toggleLink = panel.querySelector('.vc-toggle-filter');
const config = panelConfig['eventlog-sys'];
if (toggleLink && !toggleLink.hasAttribute('data-listener')) {
toggleLink.setAttribute('data-listener', 'true');
toggleLink.addEventListener('click', async function(e) {
e.preventDefault();
config.filtered = !config.filtered;
this.textContent = config.filtered ? 'Show All' : 'Plugin Only';
this.setAttribute('data-filtered', config.filtered ? '1' : '0');
if (logPanel) {
logPanel.textContent = chimpmaticLite.i18n?.loading || 'Loading...';
try {
const data = await getDebugLog(config.filtered);
logPanel.textContent = data.success ? (data.logs || data.message) : 'Error: ' + (data.message || 'Unknown error');
} catch (error) {
logPanel.textContent = chimpmaticLite.i18n?.error || 'Error loading logs';
}
}
});
}
if (logPanel && typeof chimpmaticLite !== 'undefined') {
logPanel.textContent = chimpmaticLite.i18n?.loading || 'Loading...';
try {
const data = await getDebugLog(config.filtered);
logPanel.textContent = data.success ? (data.logs || data.message) : 'Error: ' + (data.message || 'Unknown error');
} catch (error) {
logPanel.textContent = chimpmaticLite.i18n?.error || 'Error loading logs';
}
}
}
},
'cmatic-test-container': {
useModal: true
}
};
function hidePanel(panel, button) {
if (!panel) return;
const isVisible = window.getComputedStyle(panel).display !== 'none';
if (!isVisible) return;
panel.style.transition = 'opacity 0.5s ease-out';
panel.style.opacity = '0';
setTimeout(() => {
panel.style.display = 'none';
panel.style.removeProperty('opacity');
panel.style.removeProperty('transition');
}, 500);
if (button) button.setAttribute('aria-expanded', 'false');
}
function showPanel(panel, button, config) {
if (!panel) return;
panel.style.opacity = '0';
panel.style.display = 'block';
panel.style.transition = 'opacity 0.5s ease-in';
setTimeout(() => { panel.style.opacity = '1'; }, 50);
if (button) button.setAttribute('aria-expanded', 'true');
if (config && config.onOpen) {
config.onOpen(panel);
}
}
function closeAllPanels() {
const buttons = accordionContainer.querySelectorAll('.cmatic-accordion-btn');
buttons.forEach(btn => {
const panelId = btn.getAttribute('aria-controls');
if (panelId) {
const panel = document.getElementById(panelId);
hidePanel(panel, btn);
}
});
}
accordionContainer.addEventListener('click', function(event) {
const button = event.target.closest('.cmatic-accordion-btn');
if (!button) return;
event.preventDefault();
const panelId = button.getAttribute('aria-controls');
if (!panelId) return;
const config = panelConfig[panelId] || {};
if (config.useModal) {
return;
}
const panel = document.getElementById(panelId);
if (!panel) return;
const isExpanded = button.getAttribute('aria-expanded') === 'true';
if (isExpanded) {
hidePanel(panel, button);
} else {
closeAllPanels();
setTimeout(() => {
showPanel(panel, button, config);
}, 100);
}
});
const buttons = accordionContainer.querySelectorAll('.cmatic-accordion-btn');
buttons.forEach(btn => {
const panelId = btn.getAttribute('aria-controls');
const config = panelConfig[panelId] || {};
if (panelId && !config.useModal) {
const panel = document.getElementById(panelId);
if (panel) {
panel.style.display = 'none';
}
}
btn.setAttribute('aria-expanded', 'false');
});
})();
function relocateSidebarElements() {
const moveElements = document.querySelectorAll('.mce-move');
const submitDiv = document.getElementById('submitdiv');
const postboxContainer = document.querySelector('.postbox-container');
if (!moveElements.length || !submitDiv || !postboxContainer) return;
let insertAfter = submitDiv;
moveElements.forEach((el) => {
if (insertAfter.nextSibling) {
postboxContainer.insertBefore(el, insertAfter.nextSibling);
} else {
postboxContainer.appendChild(el);
}
insertAfter = el;
el.classList.add('mce-fade-in');
el.classList.remove('mce-hidden');
});
}
relocateSidebarElements();
async function fetchFieldsForSelectedList() {
if (isProFieldPanelActive) return;
const listDropdown = document.getElementById('wpcf7-mailchimp-list');
const fetchFieldsButton = document.getElementById('mce_fetch_fields');
const formId = getFormId();
if (!listDropdown || !listDropdown.value || !formId) return;
const listId = listDropdown.value;
const originalText = fetchFieldsButton ? (fetchFieldsButton.value || fetchFieldsButton.textContent) : 'Sync Fields';
if (fetchFieldsButton) {
fetchFieldsButton.disabled = true;
if (fetchFieldsButton.tagName === 'INPUT') fetchFieldsButton.value = 'Syncing Fields...';
else fetchFieldsButton.textContent = 'Syncing Fields...';
}
try {
const response = await fetch(`${chimpmaticLite.restUrl}merge-fields`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': chimpmaticLite.restNonce
},
body: JSON.stringify({ form_id: formId, list_id: listId })
});
const data = await response.json();
if (data.success && data.merge_fields) {
updateFieldLabels(data.merge_fields);
applyFuzzyMatching(data.merge_fields);
const listDropdownEl = document.getElementById('wpcf7-mailchimp-list');
const selectedId = listDropdownEl ? listDropdownEl.value : '';
const selectedList = cachedLists.find(l => l.id === selectedId);
const fieldCount = selectedList ? selectedList.field_count : 0;
const audienceName = selectedList ? selectedList.name : '';
updateFieldsNotice(fieldCount, chimpmaticLite.liteFieldsLimit || 4, audienceName);
if (fetchFieldsButton) {
if (fetchFieldsButton.tagName === 'INPUT') fetchFieldsButton.value = 'Synced ✓';
else fetchFieldsButton.textContent = 'Synced ✓';
setTimeout(() => {
if (fetchFieldsButton.tagName === 'INPUT') fetchFieldsButton.value = originalText;
else fetchFieldsButton.textContent = originalText;
fetchFieldsButton.disabled = false;
}, 1000);
}
} else {
alert('Failed to load fields. Please try again.');
if (fetchFieldsButton) {
if (fetchFieldsButton.tagName === 'INPUT') fetchFieldsButton.value = originalText;
else fetchFieldsButton.textContent = originalText;
fetchFieldsButton.disabled = false;
}
}
} catch (error) {
alert('Error loading fields. Check console for details.');
if (fetchFieldsButton) {
if (fetchFieldsButton.tagName === 'INPUT') fetchFieldsButton.value = originalText;
else fetchFieldsButton.textContent = originalText;
fetchFieldsButton.disabled = false;
}
}
}
function attachFetchFieldsListeners() {
const listDropdown = document.getElementById('wpcf7-mailchimp-list');
if (listDropdown) {
listDropdown.removeEventListener('change', handleListChange);
listDropdown.addEventListener('change', handleListChange);
}
const fetchFieldsButton = document.getElementById('mce_fetch_fields');
if (fetchFieldsButton) {
fetchFieldsButton.removeEventListener('click', handleFetchFieldsClick);
fetchFieldsButton.addEventListener('click', handleFetchFieldsClick);
}
}
function handleListChange(e) {
const selectedList = e.target.value;
const fetchFieldsButton = document.getElementById('mce_fetch_fields');
const listDropdown = e.target;
if (isProFieldPanelActive) return;
Array.from(listDropdown.options).forEach(opt => {
opt.defaultSelected = (opt.value === selectedList);
});
if (selectedList) {
if (fetchFieldsButton) fetchFieldsButton.disabled = false;
for (let i = 3; i <= 8; i++) {
const dropdown = document.getElementById(`wpcf7-mailchimp-field${i}`);
if (dropdown) dropdown.value = ' ';
}
fetchFieldsForSelectedList();
} else {
if (fetchFieldsButton) fetchFieldsButton.disabled = true;
}
}
async function handleFetchFieldsClick(event) {
if (isProFieldPanelActive) return;
event.preventDefault();
await fetchFieldsForSelectedList();
}
attachFetchFieldsListeners();
const initialListDropdown = document.getElementById('wpcf7-mailchimp-list');
const initialFetchButton = document.getElementById('mce_fetch_fields');
if (initialListDropdown && initialListDropdown.options.length > 0) {
if (!initialListDropdown.value || initialListDropdown.value === '' || initialListDropdown.value === ' ') {
initialListDropdown.value = initialListDropdown.options[0].value;
if (initialFetchButton) initialFetchButton.disabled = false;
} else {
if (initialFetchButton && initialFetchButton.disabled) initialFetchButton.disabled = false;
}
}
if (chimpmaticLite.mergeFields && chimpmaticLite.mergeFields.length > 0) {
updateFieldLabels(chimpmaticLite.mergeFields);
}
function initLicenseResetButton() {
const button = document.getElementById('cmatic-license-reset-btn');
const messageDiv = document.getElementById('cmatic-license-reset-message');
if (!button || !messageDiv) return;
button.addEventListener('click', async function(e) {
e.preventDefault();
button.disabled = true;
button.textContent = 'Resetting...';
messageDiv.innerHTML = '';
try {
const response = await fetch(chimpmaticLite.licenseResetUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': chimpmaticLite.nonce
},
credentials: 'same-origin',
body: JSON.stringify({ type: 'nuclear' })
});
const data = await response.json();
if (data.success) {
button.textContent = 'Done Resetting';
messageDiv.innerHTML = '✓ ' + escapeHtml(data.message) + '
' +
'Deleted ' + data.deleted_counts.options + ' options and ' +
data.deleted_counts.transients + ' transients';
setTimeout(function() {
button.textContent = 'Reset License Data';
button.disabled = false;
messageDiv.innerHTML = '';
}, 3000);
} else {
button.textContent = 'Reset License Data';
button.disabled = false;
messageDiv.innerHTML = '✗ Error: ' +
escapeHtml(data.message || 'Unknown error occurred') + '';
setTimeout(function() { messageDiv.innerHTML = ''; }, 5000);
}
} catch (error) {
button.textContent = 'Reset License Data';
button.disabled = false;
messageDiv.innerHTML = '✗ Network error: ' +
escapeHtml(error.message) + '';
setTimeout(function() { messageDiv.innerHTML = ''; }, 5000);
}
});
}
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
initLicenseResetButton();
let formHandlerAttached = false;
function openTestModal() {
const modal = document.getElementById('cmatic-test-modal');
if (!modal) return;
modal.classList.add('cmatic-modal--active');
document.body.classList.add('cmatic-modal-open');
const form = modal.querySelector('.wpcf7 form');
if (form && !form.querySelector('input[name="_cmatic_test_modal"]')) {
const hidden = document.createElement('input');
hidden.type = 'hidden';
hidden.name = '_cmatic_test_modal';
hidden.value = '1';
form.appendChild(hidden);
}
if (!formHandlerAttached) {
if (form) {
attachTestFormHandler(form);
formHandlerAttached = true;
}
}
const closeBtn = modal.querySelector('.cmatic-modal__close');
if (closeBtn) closeBtn.focus();
}
function closeTestModal() {
const modal = document.getElementById('cmatic-test-modal');
if (!modal) return;
modal.classList.remove('cmatic-modal--active');
document.body.classList.remove('cmatic-modal-open');
}
function attachTestFormHandler(form) {
form.addEventListener('submit', async function(e) {
e.preventDefault();
const submitBtn = form.querySelector('input[type="submit"], button[type="submit"]');
const headerSubmitBtn = document.querySelector('.cmatic-modal__submit');
const responseOutput = form.querySelector('.wpcf7-response-output') || createResponseOutput(form);
const formId = form.querySelector('input[name="_wpcf7"]')?.value;
if (!formId) {
showResponse(responseOutput, 'error', 'Form ID not found.');
return;
}
const originalBtnText = submitBtn?.value || submitBtn?.textContent;
if (submitBtn) {
submitBtn.disabled = true;
if (submitBtn.tagName === 'INPUT') {
submitBtn.value = 'Sending...';
} else {
submitBtn.textContent = 'Sending...';
}
}
if (headerSubmitBtn) {
headerSubmitBtn.disabled = true;
headerSubmitBtn.textContent = 'Submitting...';
headerSubmitBtn.classList.remove('cmatic-modal__submit--success', 'cmatic-modal__submit--error');
}
responseOutput.textContent = '';
responseOutput.className = 'wpcf7-response-output';
responseOutput.style.display = 'none';
hideChimpmaticFeedback();
let isSuccess = false;
try {
const formData = new FormData(form);
const restUrl = chimpmaticLite.restUrl.replace('chimpmatic-lite/v1/', '') + 'contact-form-7/v1/contact-forms/' + formId + '/feedback';
const response = await fetch(restUrl, {
method: 'POST',
body: formData,
credentials: 'same-origin'
});
const data = await response.json();
if (data.chimpmatic) {
showChimpmaticFeedback(data.chimpmatic);
}
if (data.status === 'mail_sent') {
isSuccess = true;
showResponse(responseOutput, 'success', data.message || 'Message sent successfully.');
form.reset();
refreshDebugLogsAfterSubmission();
} else if (data.status === 'validation_failed' || data.status === 'mail_failed') {
showResponse(responseOutput, 'error', data.message || 'There was an error sending your message.');
if (data.invalid_fields) {
data.invalid_fields.forEach(field => {
const wrap = form.querySelector(`.wpcf7-form-control-wrap[data-name="${field.field}"]`);
if (wrap) {
const tip = document.createElement('span');
tip.className = 'wpcf7-not-valid-tip';
tip.textContent = field.message;
wrap.appendChild(tip);
}
});
}
} else {
showResponse(responseOutput, 'error', data.message || 'An error occurred.');
}
} catch (error) {
console.error('Test form submission error:', error);
showResponse(responseOutput, 'error', 'Network error. Please try again.');
} finally {
if (submitBtn) {
submitBtn.disabled = false;
if (submitBtn.tagName === 'INPUT') {
submitBtn.value = originalBtnText;
} else {
submitBtn.textContent = originalBtnText;
}
}
if (headerSubmitBtn) {
headerSubmitBtn.disabled = false;
if (isSuccess) {
headerSubmitBtn.textContent = 'Success!';
headerSubmitBtn.classList.add('cmatic-modal__submit--success');
} else {
headerSubmitBtn.textContent = 'Error';
headerSubmitBtn.classList.add('cmatic-modal__submit--error');
}
setTimeout(() => {
headerSubmitBtn.textContent = 'Submit';
headerSubmitBtn.classList.remove('cmatic-modal__submit--success', 'cmatic-modal__submit--error');
}, 2000);
}
}
});
form.addEventListener('input', function(e) {
const wrap = e.target.closest('.wpcf7-form-control-wrap');
if (wrap) {
const tip = wrap.querySelector('.wpcf7-not-valid-tip');
if (tip) tip.remove();
}
});
}
function createResponseOutput(form) {
const output = document.createElement('div');
output.className = 'wpcf7-response-output';
output.setAttribute('aria-live', 'polite');
form.appendChild(output);
return output;
}
function showResponse(element, type, message) {
element.textContent = message;
element.style.display = 'block';
element.className = 'wpcf7-response-output';
if (type === 'success') {
element.classList.add('wpcf7-mail-sent-ok');
element.style.borderColor = '#00a32a';
element.style.background = '#edfaef';
} else {
element.classList.add('wpcf7-mail-sent-ng');
element.style.borderColor = '#d63638';
element.style.background = '#fcf0f1';
}
}
function showChimpmaticFeedback(chimpmatic) {
const modal = document.getElementById('cmatic-test-modal');
if (!modal) return;
const feedback = modal.querySelector('.cmatic-modal__feedback');
if (!feedback) return;
const icon = feedback.querySelector('.cmatic-modal__feedback-icon');
const title = feedback.querySelector('.cmatic-modal__feedback-title');
const details = feedback.querySelector('.cmatic-modal__feedback-details');
feedback.classList.remove('cmatic-modal__feedback--success', 'cmatic-modal__feedback--error', 'cmatic-modal__feedback--skipped');
if (chimpmatic.success === true) {
feedback.classList.add('cmatic-modal__feedback--success');
icon.innerHTML = '';
title.textContent = chimpmatic.message;
const sent = chimpmatic.merge_vars || {};
const received = chimpmatic.received || {};
const allKeys = new Set([...Object.keys(sent), ...Object.keys(received)]);
if (allKeys.size > 0) {
let tableHtml = '
| Field | Sent | Received |
|---|---|---|
| ' + escapeHtml(key) + ' | ' + sentVal + ' | ' + recvVal + ' |