Files
att-consent/admin/js/admin.js
Steve Hanlon 2294c8eda7 Security hardening and accessibility improvements (v1.1.0)
Address findings from security audit: wrap inline JSON.parse in
try/catch to prevent consent flow failure on corrupted cookies,
allowlist admin tab parameter, clamp consent_expiry server-side,
escape all server values in admin JS table builder, fix focus trap
listener cleanup, add aria-labelledby and banner focus for screen
readers, skip frontend loading during AJAX.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:32:16 +00:00

166 lines
5.0 KiB
JavaScript

/* global jQuery, attCCAdmin */
(function($) {
'use strict';
$(function() {
// Initialize color pickers.
$('.att-cc-color-picker').wpColorPicker();
// Toggle gtag/GTM fields based on tracking mode.
var $trackingMode = $('#tracking_mode');
function toggleTrackingFields() {
var mode = $trackingMode.val();
$('.att-cc-gtag-row').toggle(mode === 'gtag');
$('.att-cc-gtm-row').toggle(mode === 'gtm');
}
if ($trackingMode.length) {
toggleTrackingFields();
$trackingMode.on('change', toggleTrackingFields);
}
// --- Custom Scripts CRUD ---
var $modal = $('#att-cc-script-modal');
var $form = $('#att-cc-script-form');
var $title = $('#att-cc-script-modal-title');
var $scriptId = $('#att-cc-script-id');
// Open modal for new script.
$('#att-cc-add-script').on('click', function() {
resetForm();
$title.text('Add Script');
$modal.show();
});
// Close modal.
$('.att-cc-close-modal, .att-cc-modal__overlay').on('click', function() {
$modal.hide();
});
// Escape key closes modal.
$(document).on('keydown', function(e) {
if (e.key === 'Escape' && $modal.is(':visible')) {
$modal.hide();
}
});
// Edit script.
$(document).on('click', '.att-cc-edit-script', function() {
var id = $(this).data('id');
$.post(attCCAdmin.ajaxUrl, {
action: 'att_cc_get_script',
nonce: attCCAdmin.nonce,
script_id: id,
}, function(response) {
if (response.success) {
var s = response.data;
$scriptId.val(s.id);
$('#att-cc-script-name').val(s.name);
$('#att-cc-script-category').val(s.category);
$('#att-cc-script-placement').val(s.placement);
$('#att-cc-script-priority').val(s.priority);
$('#att-cc-script-status').val(s.status);
$('#att-cc-script-snippet').val(s.snippet);
$title.text('Edit Script');
$modal.show();
}
});
});
// Delete script.
$(document).on('click', '.att-cc-delete-script', function() {
if (!confirm(attCCAdmin.strings.confirmDelete)) {
return;
}
var id = $(this).data('id');
$.post(attCCAdmin.ajaxUrl, {
action: 'att_cc_delete_script',
nonce: attCCAdmin.nonce,
script_id: id,
}, function(response) {
if (response.success) {
refreshScriptsTable(response.data.scripts);
} else {
alert(attCCAdmin.strings.error);
}
});
});
// Save script (form submit).
$form.on('submit', function(e) {
e.preventDefault();
var data = {
action: 'att_cc_save_script',
nonce: attCCAdmin.nonce,
script_id: $scriptId.val(),
name: $('#att-cc-script-name').val(),
snippet: $('#att-cc-script-snippet').val(),
category: $('#att-cc-script-category').val(),
placement: $('#att-cc-script-placement').val(),
status: $('#att-cc-script-status').val(),
priority: $('#att-cc-script-priority').val(),
};
$.post(attCCAdmin.ajaxUrl, data, function(response) {
if (response.success) {
$modal.hide();
refreshScriptsTable(response.data.scripts);
} else {
alert(attCCAdmin.strings.error);
}
});
});
function resetForm() {
$scriptId.val('');
$('#att-cc-script-name').val('');
$('#att-cc-script-category').val('analytics');
$('#att-cc-script-placement').val('head');
$('#att-cc-script-priority').val('10');
$('#att-cc-script-status').val('active');
$('#att-cc-script-snippet').val('');
}
function refreshScriptsTable(scripts) {
var $tbody = $('#att-cc-scripts-list');
$tbody.empty();
if (!scripts || scripts.length === 0) {
$tbody.append('<tr class="att-cc-no-scripts"><td colspan="6">No custom scripts added yet.</td></tr>');
return;
}
scripts.forEach(function(s) {
var eCat = escapeHtml(s.category);
var eStatus = escapeHtml(s.status);
var ePlacement = escapeHtml(s.placement);
var ePriority = escapeHtml(String(s.priority));
var eId = escapeHtml(String(s.id));
var row = '<tr data-id="' + eId + '">' +
'<td class="column-name">' + escapeHtml(s.name) + '</td>' +
'<td class="column-category"><span class="att-cc-badge att-cc-badge--' + eCat + '">' + capitalize(eCat) + '</span></td>' +
'<td class="column-placement">' + capitalize(ePlacement) + '</td>' +
'<td class="column-priority">' + ePriority + '</td>' +
'<td class="column-status"><span class="att-cc-status att-cc-status--' + eStatus + '">' + capitalize(eStatus) + '</span></td>' +
'<td class="column-actions">' +
'<button type="button" class="button button-small att-cc-edit-script" data-id="' + eId + '">Edit</button> ' +
'<button type="button" class="button button-small button-link-delete att-cc-delete-script" data-id="' + eId + '">Delete</button>' +
'</td>' +
'</tr>';
$tbody.append(row);
});
}
function escapeHtml(text) {
var div = document.createElement('div');
div.appendChild(document.createTextNode(text));
return div.innerHTML;
}
function capitalize(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
});
})(jQuery);