forked from LiveCarta/LiveCartaWP
2042 lines
67 KiB
JavaScript
2042 lines
67 KiB
JavaScript
/**
|
|
* 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' ? '<span class="mce-required">Required</span>' : '';
|
|
label.innerHTML = `${field.name} - *|${field.tag}|* <span class="mce-type">${field.type}</span> ${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 ? '<strong>' + audienceName + '</strong> ' : '';
|
|
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 += `<option value="${list.id}"${selected}>${optionText}</option>`;
|
|
});
|
|
|
|
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 = '<span style="color: #46b450;">✓ ' + escapeHtml(data.message) + '</span><br>' +
|
|
'<small style="color: #666;">Deleted ' + data.deleted_counts.options + ' options and ' +
|
|
data.deleted_counts.transients + ' transients</small>';
|
|
|
|
setTimeout(function() {
|
|
button.textContent = 'Reset License Data';
|
|
button.disabled = false;
|
|
messageDiv.innerHTML = '';
|
|
}, 3000);
|
|
} else {
|
|
button.textContent = 'Reset License Data';
|
|
button.disabled = false;
|
|
messageDiv.innerHTML = '<span style="color: #dc3232;">✗ Error: ' +
|
|
escapeHtml(data.message || 'Unknown error occurred') + '</span>';
|
|
|
|
setTimeout(function() { messageDiv.innerHTML = ''; }, 5000);
|
|
}
|
|
} catch (error) {
|
|
button.textContent = 'Reset License Data';
|
|
button.disabled = false;
|
|
messageDiv.innerHTML = '<span style="color: #dc3232;">✗ Network error: ' +
|
|
escapeHtml(error.message) + '</span>';
|
|
|
|
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 = '<span class="dashicons dashicons-yes-alt"></span>';
|
|
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 = '<table class="cmatic-modal__feedback-table">';
|
|
tableHtml += '<thead><tr><th>Field</th><th>Sent</th><th>Received</th></tr></thead><tbody>';
|
|
|
|
for (const key of allKeys) {
|
|
const sentVal = sent[key] !== undefined ? escapeHtml(String(sent[key])) : '<span class="field-empty">—</span>';
|
|
const recvVal = received[key] !== undefined ? escapeHtml(String(received[key])) : '<span class="field-empty">—</span>';
|
|
const mismatch = sent[key] !== undefined && received[key] !== undefined && String(sent[key]) !== String(received[key]);
|
|
const rowClass = mismatch ? ' class="field-mismatch"' : '';
|
|
tableHtml += '<tr' + rowClass + '><td class="field-key">' + escapeHtml(key) + '</td><td>' + sentVal + '</td><td>' + recvVal + '</td></tr>';
|
|
}
|
|
|
|
tableHtml += '</tbody></table>';
|
|
details.innerHTML = tableHtml;
|
|
} else {
|
|
details.innerHTML = '';
|
|
}
|
|
} else if (chimpmatic.skipped === true) {
|
|
feedback.classList.add('cmatic-modal__feedback--skipped');
|
|
icon.innerHTML = '<span class="dashicons dashicons-info-outline"></span>';
|
|
title.textContent = 'Subscription skipped';
|
|
details.textContent = chimpmatic.message;
|
|
} else {
|
|
feedback.classList.add('cmatic-modal__feedback--error');
|
|
icon.innerHTML = '<span class="dashicons dashicons-dismiss"></span>';
|
|
title.textContent = 'Subscription failed';
|
|
details.textContent = chimpmatic.message;
|
|
}
|
|
|
|
feedback.style.display = 'flex';
|
|
}
|
|
|
|
function hideChimpmaticFeedback() {
|
|
const modal = document.getElementById('cmatic-test-modal');
|
|
if (!modal) return;
|
|
|
|
const feedback = modal.querySelector('.cmatic-modal__feedback');
|
|
if (feedback) {
|
|
feedback.style.display = 'none';
|
|
}
|
|
}
|
|
|
|
async function refreshDebugLogsAfterSubmission() {
|
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
|
|
const logPanelContainer = document.getElementById('eventlog-sys');
|
|
const logPanel = document.getElementById('log_panel');
|
|
const debugLogBtn = document.querySelector('.cme-trigger-log');
|
|
|
|
if (!logPanelContainer || !logPanel) return;
|
|
|
|
const isLogVisible = window.getComputedStyle(logPanelContainer).display !== 'none';
|
|
if (!isLogVisible) {
|
|
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);
|
|
if (debugLogBtn) debugLogBtn.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;
|
|
}
|
|
}
|
|
|
|
document.addEventListener('click', function(event) {
|
|
const btn = event.target.closest('.vc-test-submission');
|
|
if (!btn) return;
|
|
|
|
event.preventDefault();
|
|
openTestModal();
|
|
});
|
|
|
|
document.addEventListener('click', function(event) {
|
|
const closeBtn = event.target.closest('#cmatic-test-modal .cmatic-modal__close');
|
|
if (!closeBtn) return;
|
|
|
|
event.preventDefault();
|
|
closeTestModal();
|
|
});
|
|
|
|
document.addEventListener('click', function(event) {
|
|
const overlay = event.target.closest('#cmatic-test-modal .cmatic-modal__overlay');
|
|
if (!overlay) return;
|
|
|
|
closeTestModal();
|
|
});
|
|
|
|
document.addEventListener('keydown', function(event) {
|
|
if (event.key === 'Escape') {
|
|
const modal = document.getElementById('cmatic-test-modal');
|
|
if (modal && modal.classList.contains('cmatic-modal--active')) {
|
|
closeTestModal();
|
|
}
|
|
}
|
|
});
|
|
|
|
document.addEventListener('click', function(event) {
|
|
const submitBtn = event.target.closest('#cmatic-test-modal .cmatic-modal__submit');
|
|
if (!submitBtn) return;
|
|
|
|
event.preventDefault();
|
|
const modal = document.getElementById('cmatic-test-modal');
|
|
if (!modal) return;
|
|
|
|
const form = modal.querySelector('.wpcf7 form');
|
|
if (!form) return;
|
|
|
|
form.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }));
|
|
});
|
|
});
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const eye = document.querySelector('.cmatic-eye');
|
|
const input = document.getElementById('cmatic-api');
|
|
if (!eye || !input) return;
|
|
|
|
let cachedRealKey = null;
|
|
|
|
eye.addEventListener('click', async function(e) {
|
|
e.preventDefault();
|
|
const icon = this.querySelector('.dashicons');
|
|
const isMasked = input.dataset.isMasked === '1';
|
|
const hasKey = input.dataset.hasKey === '1';
|
|
|
|
if (isMasked && hasKey) {
|
|
if (!cachedRealKey) {
|
|
const formId = typeof chimpmaticLite !== 'undefined' ? chimpmaticLite.formId : 0;
|
|
if (!formId) {
|
|
console.warn('ChimpMatic: No form ID available');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
eye.style.opacity = '0.5';
|
|
const response = await fetch(
|
|
`${chimpmaticLite.restUrl}api-key/${formId}`,
|
|
{
|
|
method: 'GET',
|
|
headers: {
|
|
'X-WP-Nonce': chimpmaticLite.restNonce,
|
|
'Content-Type': 'application/json'
|
|
}
|
|
}
|
|
);
|
|
|
|
if (!response.ok) {
|
|
throw new Error('Failed to fetch API key');
|
|
}
|
|
|
|
const data = await response.json();
|
|
cachedRealKey = data.api_key || '';
|
|
} catch (err) {
|
|
console.error('ChimpMatic: Error fetching API key', err);
|
|
eye.style.opacity = '1';
|
|
return;
|
|
}
|
|
eye.style.opacity = '1';
|
|
}
|
|
|
|
input.value = cachedRealKey;
|
|
input.dataset.isMasked = '0';
|
|
icon.classList.remove('dashicons-visibility');
|
|
icon.classList.add('dashicons-hidden');
|
|
} else {
|
|
input.value = input.dataset.maskedKey;
|
|
input.dataset.isMasked = '1';
|
|
icon.classList.remove('dashicons-hidden');
|
|
icon.classList.add('dashicons-visibility');
|
|
}
|
|
});
|
|
|
|
const form = input.closest('form');
|
|
if (form) {
|
|
form.addEventListener('submit', async function(e) {
|
|
const isMasked = input.dataset.isMasked === '1';
|
|
const hasKey = input.dataset.hasKey === '1';
|
|
|
|
if (isMasked && hasKey) {
|
|
if (cachedRealKey) {
|
|
input.value = cachedRealKey;
|
|
} else {
|
|
const formId = typeof chimpmaticLite !== 'undefined' ? chimpmaticLite.formId : 0;
|
|
if (formId) {
|
|
e.preventDefault();
|
|
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) {
|
|
const data = await response.json();
|
|
cachedRealKey = data.api_key || '';
|
|
input.value = cachedRealKey;
|
|
}
|
|
} catch (err) {
|
|
console.error('ChimpMatic: Error fetching API key for submit', err);
|
|
}
|
|
form.submit();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
(function initContactLookup() {
|
|
const lookupBtn = document.getElementById('cmatic-lookup-btn');
|
|
const emailInput = document.getElementById('cmatic-lookup-email');
|
|
const resultsContainer = document.getElementById('cmatic-lookup-results');
|
|
const formContainer = emailInput ? emailInput.closest('div') : null;
|
|
|
|
if (!lookupBtn || !emailInput || !resultsContainer || !formContainer) {
|
|
return;
|
|
}
|
|
|
|
function showForm() {
|
|
formContainer.classList.remove('cmatic-hidden');
|
|
resultsContainer.classList.add('cmatic-hidden');
|
|
resultsContainer.innerHTML = '';
|
|
emailInput.value = '';
|
|
emailInput.focus();
|
|
}
|
|
|
|
function formatDate(dateStr) {
|
|
if (!dateStr) return null;
|
|
const date = new Date(dateStr);
|
|
return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
|
|
}
|
|
|
|
function getStatusInfo(status) {
|
|
const statusMap = {
|
|
'subscribed': { class: 'cmatic-status-subscribed', badge: 'cmatic-badge-success', label: 'Subscribed' },
|
|
'unsubscribed': { class: 'cmatic-status-unsubscribed', badge: 'cmatic-badge-neutral', label: 'Unsubscribed' },
|
|
'pending': { class: 'cmatic-status-pending', badge: 'cmatic-badge-warning', label: 'Pending' },
|
|
'cleaned': { class: 'cmatic-status-unsubscribed', badge: 'cmatic-badge-neutral', label: 'Cleaned' },
|
|
'archived': { class: 'cmatic-status-not-found', badge: 'cmatic-badge-neutral', label: 'Archived' },
|
|
'not_subscribed': { class: 'cmatic-status-not-found', badge: 'cmatic-badge-neutral', label: 'Not Found' }
|
|
};
|
|
return statusMap[status] || { class: 'cmatic-status-not-found', badge: 'cmatic-badge-neutral', label: status };
|
|
}
|
|
|
|
function renderMergeFields(mergeFields) {
|
|
if (!mergeFields || Object.keys(mergeFields).length === 0) {
|
|
return '<span class="cmatic-empty">No fields</span>';
|
|
}
|
|
|
|
const fieldLabels = {
|
|
'EMAIL': 'Email', 'FNAME': 'First Name', 'LNAME': 'Last Name',
|
|
'PHONE': 'Phone', 'ADDRESS': 'Address', 'BIRTHDAY': 'Birthday',
|
|
'COMPANY': 'Company', 'WEBSITE': 'Website', 'AGE': 'Age',
|
|
'GENDER': 'Gender', 'ZIPCODE': 'Zip Code', 'MMERGE3': 'Field 3',
|
|
'MMERGE4': 'Field 4', 'MMERGE5': 'Field 5', 'MMERGE6': 'Field 6'
|
|
};
|
|
|
|
let rows = '';
|
|
for (const [key, value] of Object.entries(mergeFields)) {
|
|
const fieldKey = key.toLowerCase();
|
|
if (typeof value === 'object' && value !== null) {
|
|
if (value.addr1 || value.city || value.state || value.zip || value.country) {
|
|
const addrParts = [value.addr1, value.addr2, value.city, value.state, value.zip, value.country].filter(Boolean);
|
|
const label = fieldLabels[key] || key;
|
|
rows += `<tr data-field="${fieldKey}"><th>${label}</th><td class="cmatic-val">${addrParts.length ? addrParts.join(', ') : '—'}</td></tr>`;
|
|
}
|
|
continue;
|
|
}
|
|
const label = fieldLabels[key] || key;
|
|
const displayValue = (value && value !== '') ? value : '—';
|
|
rows += `<tr data-field="${fieldKey}"><th>${label}</th><td class="cmatic-val">${displayValue}</td></tr>`;
|
|
}
|
|
|
|
if (!rows) return '<span class="cmatic-empty">No fields configured</span>';
|
|
return `<table class="cmatic-field-table">${rows}</table>`;
|
|
}
|
|
|
|
function renderTags(tags) {
|
|
if (!tags || tags.length === 0) {
|
|
return '<div data-section="tags"><span class="cmatic-empty">No tags</span></div>';
|
|
}
|
|
return '<div data-section="tags" class="cmatic-tag-list">' +
|
|
tags.map(tag => `<span class="cmatic-tag-chip cmatic-val">${tag}</span>`).join('') +
|
|
'</div>';
|
|
}
|
|
|
|
function renderInterests(interests) {
|
|
if (!interests || Object.keys(interests).length === 0) {
|
|
return '<div data-section="groups"><span class="cmatic-empty">No groups assigned</span></div>';
|
|
}
|
|
let html = '<div data-section="groups">';
|
|
for (const [category, items] of Object.entries(interests)) {
|
|
const catKey = category.toLowerCase().replace(/\s+/g, '-');
|
|
const itemsArray = Array.isArray(items) ? items : [items];
|
|
html += `<div data-group="${catKey}" style="margin-bottom: 6px;"><strong style="font-size: 10px;">${category}:</strong> `;
|
|
html += itemsArray.map(i => `<span class="cmatic-tag-chip cmatic-val">${i}</span>`).join(' ');
|
|
html += '</div>';
|
|
}
|
|
html += '</div>';
|
|
return html;
|
|
}
|
|
|
|
function renderMarketingPermissions(permissions) {
|
|
if (!permissions) {
|
|
return '<div data-section="gdpr"><span class="cmatic-empty">No GDPR permissions</span></div>';
|
|
}
|
|
|
|
const isArray = Array.isArray(permissions);
|
|
|
|
if (isArray && permissions.length === 0) {
|
|
return '<div data-section="gdpr"><span class="cmatic-empty">No GDPR permissions</span></div>';
|
|
}
|
|
if (!isArray && Object.keys(permissions).length === 0) {
|
|
return '<div data-section="gdpr"><span class="cmatic-empty">No GDPR permissions</span></div>';
|
|
}
|
|
|
|
let rows = '';
|
|
|
|
if (!isArray) {
|
|
let idx = 0;
|
|
for (const [key, value] of Object.entries(permissions)) {
|
|
const displayVal = Array.isArray(value) ? value.join(', ') : value;
|
|
rows += `<tr data-field="gdpr-${idx}"><th>Permission ${idx + 1}</th><td class="cmatic-val">${displayVal}</td></tr>`;
|
|
idx++;
|
|
}
|
|
return `<table class="cmatic-field-table" data-section="gdpr">${rows}</table>`;
|
|
}
|
|
|
|
if (typeof permissions[0] === 'string') {
|
|
permissions.forEach((hash, idx) => {
|
|
rows += `<tr data-field="gdpr-${idx}"><th>Permission ${idx + 1}</th><td class="cmatic-val">${hash}</td></tr>`;
|
|
});
|
|
return `<table class="cmatic-field-table" data-section="gdpr">${rows}</table>`;
|
|
}
|
|
|
|
permissions.forEach((perm, idx) => {
|
|
const permKey = perm.marketing_permission_id || `gdpr-${idx}`;
|
|
const enabled = perm.enabled ? '✓ Yes' : '✗ No';
|
|
rows += `<tr data-field="${permKey}"><th>${perm.text || perm.marketing_permission_id}</th><td class="cmatic-val">${enabled}</td></tr>`;
|
|
});
|
|
return `<table class="cmatic-field-table" data-section="gdpr">${rows}</table>`;
|
|
}
|
|
|
|
function getLanguageName(code) {
|
|
if (!code) return '—';
|
|
const languages = {
|
|
'en': 'English', 'es': 'Spanish', 'fr': 'French', 'de': 'German',
|
|
'pt': 'Portuguese', 'it': 'Italian', 'nl': 'Dutch', 'ru': 'Russian',
|
|
'ja': 'Japanese', 'zh': 'Chinese', 'ko': 'Korean', 'ar': 'Arabic',
|
|
'hi': 'Hindi', 'pl': 'Polish', 'tr': 'Turkish', 'vi': 'Vietnamese',
|
|
'th': 'Thai', 'sv': 'Swedish', 'da': 'Danish', 'fi': 'Finnish',
|
|
'no': 'Norwegian', 'cs': 'Czech', 'el': 'Greek', 'he': 'Hebrew',
|
|
'hu': 'Hungarian', 'id': 'Indonesian', 'ms': 'Malay', 'ro': 'Romanian',
|
|
'sk': 'Slovak', 'uk': 'Ukrainian', 'bg': 'Bulgarian', 'hr': 'Croatian',
|
|
'ca': 'Catalan', 'et': 'Estonian', 'lv': 'Latvian', 'lt': 'Lithuanian',
|
|
'sl': 'Slovenian', 'sr': 'Serbian', 'tl': 'Tagalog', 'fa': 'Persian'
|
|
};
|
|
return languages[code.toLowerCase()] || code.toUpperCase();
|
|
}
|
|
|
|
function renderPreferences(result) {
|
|
let rows = '';
|
|
|
|
const emailType = result.email_type ? result.email_type.toUpperCase() : '—';
|
|
rows += `<tr data-field="email_type"><th>Email format</th><td class="cmatic-val">${emailType}</td></tr>`;
|
|
|
|
const language = getLanguageName(result.language);
|
|
rows += `<tr data-field="language"><th>Language</th><td class="cmatic-val">${language}</td></tr>`;
|
|
|
|
const vip = result.vip ? 'Yes' : 'No';
|
|
rows += `<tr data-field="vip"><th>VIP</th><td class="cmatic-val">${vip}</td></tr>`;
|
|
|
|
if (result.member_rating !== null && result.member_rating !== undefined) {
|
|
const stars = '★'.repeat(result.member_rating) + '☆'.repeat(5 - result.member_rating);
|
|
rows += `<tr data-field="member_rating"><th>Contact rating</th><td class="cmatic-val">${stars}</td></tr>`;
|
|
} else {
|
|
rows += `<tr data-field="member_rating"><th>Contact rating</th><td class="cmatic-val">—</td></tr>`;
|
|
}
|
|
|
|
rows += `<tr data-field="email_client"><th>Email client</th><td class="cmatic-val">${result.email_client || '—'}</td></tr>`;
|
|
|
|
if (result.location && (result.location.country_code || result.location.timezone)) {
|
|
const locParts = [];
|
|
if (result.location.country_code) locParts.push(result.location.country_code);
|
|
if (result.location.region) locParts.push(result.location.region);
|
|
if (result.location.timezone) locParts.push(`(${result.location.timezone})`);
|
|
rows += `<tr data-field="location"><th>Location</th><td class="cmatic-val">${locParts.join(' ') || '—'}</td></tr>`;
|
|
} else {
|
|
rows += `<tr data-field="location"><th>Location</th><td class="cmatic-val">—</td></tr>`;
|
|
}
|
|
|
|
const smsConsent = result.consents_to_one_to_one_messaging === true ? 'Yes' :
|
|
(result.consents_to_one_to_one_messaging === false ? 'No' : '—');
|
|
rows += `<tr data-field="sms_consent"><th>SMS consent</th><td class="cmatic-val">${smsConsent}</td></tr>`;
|
|
|
|
return `<table class="cmatic-field-table" data-section="preferences">${rows}</table>`;
|
|
}
|
|
|
|
function renderResultCard(result, isFirst) {
|
|
const statusInfo = getStatusInfo(result.status);
|
|
const isFound = result.found;
|
|
|
|
let html = '<div class="cmatic-result-card">';
|
|
|
|
if (isFound) {
|
|
const expandedClass = isFirst ? ' cmatic-expanded' : '';
|
|
html += `<div class="cmatic-card-header cmatic-expandable${expandedClass}" onclick="this.classList.toggle('cmatic-expanded'); this.nextElementSibling.classList.toggle('cmatic-visible');">`;
|
|
} else {
|
|
html += '<div class="cmatic-card-header">';
|
|
}
|
|
|
|
html += `
|
|
<div class="cmatic-header-left">
|
|
<span class="cmatic-status-dot ${statusInfo.class}"></span>
|
|
<strong>${result.list_name}</strong>
|
|
</div>
|
|
<div class="cmatic-header-right">
|
|
<span class="cmatic-badge ${statusInfo.badge}">${statusInfo.label}</span>
|
|
${isFound ? '<span class="cmatic-chevron"></span>' : ''}
|
|
</div>
|
|
</div>`;
|
|
|
|
if (isFound) {
|
|
const visibleClass = isFirst ? ' cmatic-visible' : '';
|
|
html += `<div class="cmatic-card-body${visibleClass}">`;
|
|
|
|
html += '<div class="cmatic-section-header">Contact Info</div>';
|
|
html += `<div data-section="contact-info">`;
|
|
html += `<table class="cmatic-field-table"><tr data-field="source"><th>Source</th><td class="cmatic-val">${result.source || '—'}</td></tr></table>`;
|
|
html += renderMergeFields(result.merge_fields);
|
|
html += `</div>`;
|
|
|
|
html += '<div class="cmatic-section-header">Tags</div>';
|
|
html += renderTags(result.tags);
|
|
|
|
html += '<div class="cmatic-section-header">Groups</div>';
|
|
html += renderInterests(result.interests);
|
|
|
|
html += '<div class="cmatic-section-header">GDPR / Marketing Permissions</div>';
|
|
html += renderMarketingPermissions(result.marketing_permissions);
|
|
|
|
html += '<div class="cmatic-section-header">Details</div>';
|
|
html += '<table class="cmatic-field-table" data-section="details">';
|
|
html += `<tr data-field="subscribed"><th>Subscribed</th><td class="cmatic-val">${result.subscribed ? formatDate(result.subscribed) : '—'}</td></tr>`;
|
|
html += `<tr data-field="timestamp_signup"><th>Signup date</th><td class="cmatic-val">${result.timestamp_signup ? formatDate(result.timestamp_signup) : '—'}</td></tr>`;
|
|
html += `<tr data-field="ip_signup"><th>IP signup</th><td class="cmatic-val">${result.ip_signup || '—'}</td></tr>`;
|
|
html += `<tr data-field="last_changed"><th>Last changed</th><td class="cmatic-val">${result.last_changed ? formatDate(result.last_changed) : '—'}</td></tr>`;
|
|
html += `<tr data-field="unsubscribe_reason"><th>Unsubscribe reason</th><td class="cmatic-val">${result.unsubscribe_reason || '—'}</td></tr>`;
|
|
html += '</table>';
|
|
|
|
html += '<div class="cmatic-section-header">Preferences</div>';
|
|
html += renderPreferences(result);
|
|
|
|
html += '</div>';
|
|
}
|
|
|
|
html += '</div>';
|
|
return html;
|
|
}
|
|
|
|
function renderResults(data) {
|
|
let html = '';
|
|
|
|
const summaryClass = data.found ? 'cmatic-found' : 'cmatic-not-found';
|
|
html += `<div class="cmatic-lookup-summary ${summaryClass}"><strong>${data.message}</strong></div>`;
|
|
|
|
const sortedResults = [...data.results].sort((a, b) => {
|
|
if (a.found && !b.found) return -1;
|
|
if (!a.found && b.found) return 1;
|
|
return 0;
|
|
});
|
|
|
|
let firstFound = true;
|
|
sortedResults.forEach(result => {
|
|
html += renderResultCard(result, result.found && firstFound);
|
|
if (result.found) firstFound = false;
|
|
});
|
|
|
|
html += '<div style="text-align: center; margin-top: 12px; padding-top: 12px; border-top: 1px solid #eee;">';
|
|
html += '<a href="#" id="cmatic-new-lookup" style="font-size: 12px; color: #2271b1; text-decoration: none;">New Lookup</a>';
|
|
html += '</div>';
|
|
|
|
return html;
|
|
}
|
|
|
|
function applyLiteBlur() {
|
|
const freeMergeFieldCount = 6;
|
|
|
|
const proOnlyFields = [
|
|
'source', 'ip_signup', 'subscribed', 'timestamp_signup',
|
|
'member_rating', 'location', 'email_client', 'vip',
|
|
'language', 'email_type', 'sms_consent'
|
|
];
|
|
|
|
const proOnlySections = ['tags', 'groups', 'gdpr', 'preferences'];
|
|
|
|
const contactInfoSection = resultsContainer.querySelector('[data-section="contact-info"]');
|
|
if (contactInfoSection) {
|
|
const mergeFieldRows = contactInfoSection.querySelectorAll('tr[data-field]');
|
|
let mergeFieldIndex = 0;
|
|
mergeFieldRows.forEach(row => {
|
|
if (mergeFieldIndex >= freeMergeFieldCount) {
|
|
const val = row.querySelector('.cmatic-val');
|
|
if (val) val.classList.add('cmatic-not-pro');
|
|
}
|
|
mergeFieldIndex++;
|
|
});
|
|
}
|
|
|
|
proOnlyFields.forEach(field => {
|
|
const rows = resultsContainer.querySelectorAll(`tr[data-field="${field}"]`);
|
|
rows.forEach(row => {
|
|
const val = row.querySelector('.cmatic-val');
|
|
if (val) val.classList.add('cmatic-not-pro');
|
|
});
|
|
});
|
|
|
|
proOnlySections.forEach(section => {
|
|
const elements = resultsContainer.querySelectorAll(`[data-section="${section}"]`);
|
|
elements.forEach(el => {
|
|
el.querySelectorAll('.cmatic-val, .cmatic-empty, .cmatic-tag-chip').forEach(child => {
|
|
child.classList.add('cmatic-not-pro');
|
|
});
|
|
});
|
|
});
|
|
|
|
const blurredElements = resultsContainer.querySelectorAll('.cmatic-not-pro');
|
|
blurredElements.forEach(el => {
|
|
el.addEventListener('click', showUpsellTooltip);
|
|
});
|
|
}
|
|
|
|
function showUpsellTooltip(e) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
|
|
const existing = document.querySelector('.cmatic-upsell-tooltip');
|
|
if (existing) existing.remove();
|
|
|
|
const tooltip = document.createElement('div');
|
|
tooltip.className = 'cmatic-upsell-tooltip';
|
|
tooltip.innerHTML = `
|
|
<strong>Pro Feature</strong><br>
|
|
Unlock full contact insights with ChimpMatic Pro.<br><br>
|
|
<a href="https://chimpmatic.com/pro/?utm_source=plugin&utm_medium=contact-lookup&utm_campaign=upsell" target="_blank">Upgrade to Pro →</a>
|
|
`;
|
|
|
|
const rect = e.currentTarget.getBoundingClientRect();
|
|
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
|
tooltip.style.position = 'absolute';
|
|
tooltip.style.top = (rect.bottom + scrollTop + 8) + 'px';
|
|
tooltip.style.left = rect.left + 'px';
|
|
|
|
document.body.appendChild(tooltip);
|
|
|
|
setTimeout(() => {
|
|
document.addEventListener('click', function closeTooltip(evt) {
|
|
if (!tooltip.contains(evt.target)) {
|
|
tooltip.remove();
|
|
document.removeEventListener('click', closeTooltip);
|
|
}
|
|
});
|
|
}, 10);
|
|
}
|
|
|
|
lookupBtn.addEventListener('click', async function() {
|
|
const email = emailInput.value.trim();
|
|
const formId = emailInput.dataset.formId;
|
|
|
|
if (!email) {
|
|
resultsContainer.innerHTML = '<div class="cmatic-lookup-summary cmatic-not-found">Please enter an email address.</div>';
|
|
resultsContainer.classList.remove('cmatic-hidden');
|
|
return;
|
|
}
|
|
|
|
lookupBtn.disabled = true;
|
|
lookupBtn.textContent = 'Looking up...';
|
|
resultsContainer.innerHTML = '<div class="cmatic-lookup-summary" style="border-color: #72aee6; background: #f0f6fc;">Checking all audiences...</div>';
|
|
resultsContainer.classList.remove('cmatic-hidden');
|
|
|
|
try {
|
|
const response = await fetch(chimpmaticLite.restUrl + 'contact/lookup', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-WP-Nonce': chimpmaticLite.restNonce
|
|
},
|
|
body: JSON.stringify({
|
|
email: email,
|
|
form_id: parseInt(formId, 10)
|
|
})
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (!response.ok) {
|
|
throw new Error(data.message || 'Search failed');
|
|
}
|
|
|
|
formContainer.classList.add('cmatic-hidden');
|
|
resultsContainer.innerHTML = renderResults(data);
|
|
|
|
const newLookupLink = document.getElementById('cmatic-new-lookup');
|
|
if (newLookupLink) {
|
|
newLookupLink.addEventListener('click', function(e) {
|
|
e.preventDefault();
|
|
showForm();
|
|
});
|
|
}
|
|
|
|
if (!data.is_pro) {
|
|
applyLiteBlur();
|
|
}
|
|
|
|
} catch (error) {
|
|
resultsContainer.innerHTML = `<div class="cmatic-lookup-summary cmatic-not-found">Error: ${error.message}</div>`;
|
|
} finally {
|
|
lookupBtn.disabled = false;
|
|
lookupBtn.textContent = 'Lookup';
|
|
}
|
|
});
|
|
|
|
emailInput.addEventListener('keypress', function(e) {
|
|
if (e.key === 'Enter') {
|
|
lookupBtn.click();
|
|
}
|
|
});
|
|
})();
|
|
});
|