// Wrap the entire code in an IIFE (Immediately Invoked Function Expression)
// to create a private scope and avoid global variable conflicts
(function() {
// Use a local variable instead of global
let directivesLoadingState = false;
// Expose necessary functions to window/global scope
window.loadDirectives = loadDirectives;
window.handleDirectiveAction = handleDirectiveAction;
window.deleteDirective = deleteDirective;
window.loadAttributeChoices = loadAttributeChoices;
window.switchTab = switchTab;
window.submitDirective = submitDirective;
// Directives Functions
function loadDirectives() {
// Prevent multiple simultaneous requests
if (directivesLoadingState) {
console.log("Already loading directives, request ignored");
return;
}
directivesLoadingState = true;
console.log("Loading directives");
const tableBody = document.getElementById('directivesTableBody');
if (!tableBody) {
console.error('Directives table body not found');
directivesLoadingState = false;
return;
}
tableBody.innerHTML = '
Loading directives... ';
fetch('integrity_check_handler.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'action=get_directives'
})
.then(response => {
console.log("Get directives response status:", response.status);
if (!response.ok) {
throw new Error(`Server error: ${response.status}`);
}
return response.text().then(text => {
console.log("Raw directives response:", text); // Log the raw response
try {
return JSON.parse(text);
} catch (e) {
console.error("JSON parse error:", e);
throw new Error("Invalid JSON response: " + text.substring(0, 100));
}
});
})
.then(data => {
directivesLoadingState = false;
console.log("Directives data:", data);
if (!data.success) {
throw new Error(data.message || 'Failed to load directives');
}
if (!data.directives || data.directives.length === 0) {
tableBody.innerHTML = 'No directives found ';
return;
}
// Group directives by attributes to identify sets created from multiple selections
const directiveSets = groupDirectivesByAttributes(data.directives);
// Build HTML for each directive
let html = '';
for (const directive of data.directives) {
// See if this directive is part of a set (created from multiple selections)
const setKey = `${directive.attribute1_id}_${directive.attribute2_id}`;
const setInfo = directiveSets[setKey];
const isPartOfSet = setInfo && (setInfo.attr1Choices.length > 1 || setInfo.attr2Choices.length > 1);
const setDescription = isPartOfSet ?
`(Part of a set: ${setInfo.attr1Choices.length} × ${setInfo.attr2Choices.length} combinations)` : '';
// Create the row HTML
html += `
${directive.id}
${directive.attribute1_name}: ${directive.choice1}
${isPartOfSet ? `${setDescription}
` : ''}
${directive.attribute2_name}: ${directive.choice2}
${directive.status.charAt(0).toUpperCase() + directive.status.slice(1)}
${directive.status === 'pending' ? `
Approve
` : `
Revoke
`}
Delete
`;
}
tableBody.innerHTML = html;
// Add some CSS for set info
addSetInfoStyles();
})
.catch(error => {
directivesLoadingState = false;
console.error('Error loading directives:', error);
tableBody.innerHTML = `Failed to load directives: ${error.message} `;
showNotification('Failed to load directives: ' + error.message, 'error');
});
}
function groupDirectivesByAttributes(directives) {
const sets = {};
for (const directive of directives) {
const key = `${directive.attribute1_id}_${directive.attribute2_id}`;
if (!sets[key]) {
sets[key] = {
attribute1_id: directive.attribute1_id,
attribute2_id: directive.attribute2_id,
attribute1_name: directive.attribute1_name,
attribute2_name: directive.attribute2_name,
attr1Choices: [],
attr2Choices: []
};
}
// Add choices if they don't exist in the array
if (!sets[key].attr1Choices.includes(directive.choice1)) {
sets[key].attr1Choices.push(directive.choice1);
}
if (!sets[key].attr2Choices.includes(directive.choice2)) {
sets[key].attr2Choices.push(directive.choice2);
}
}
return sets;
}
function addSetInfoStyles() {
// Check if the styles are already added
if (document.getElementById('set-info-styles')) return;
const style = document.createElement('style');
style.id = 'set-info-styles';
style.textContent = `
.set-info {
font-size: 0.75rem;
color: var(--gray-500);
margin-top: 0.25rem;
font-style: italic;
}
`;
document.head.appendChild(style);
}
function submitDirective() {
const attribute1Select = document.getElementById('attribute1');
const attribute2Select = document.getElementById('attribute2');
const choice1Select = document.getElementById('choice1');
const choice2Select = document.getElementById('choice2');
if (!attribute1Select.value || !attribute2Select.value || !choice1Select.value || !choice2Select.value) {
showNotification('Please select all fields', 'error');
return;
}
if (attribute1Select.value === attribute2Select.value) {
showNotification('Please select two different attributes', 'error');
return;
}
const directiveData = {
attribute1_id: attribute1Select.value,
attribute2_id: attribute2Select.value,
choice1: choice1Select.value,
choice2: choice2Select.value
};
console.log("Submitting new directive:", directiveData);
fetch('integrity_check_handler.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `action=add_directive&data=${encodeURIComponent(JSON.stringify(directiveData))}`
})
.then(response => {
console.log("Add directive response status:", response.status);
if (!response.ok) {
throw new Error(`Server error: ${response.status}`);
}
return response.text().then(text => {
console.log("Raw response:", text); // Log the raw response
try {
return JSON.parse(text);
} catch (e) {
console.error("JSON parse error:", e);
throw new Error("Invalid JSON response: " + text.substring(0, 100));
}
});
})
.then(data => {
console.log("Add directive data:", data);
if (data.success) {
// Reset form
attribute1Select.value = '';
attribute2Select.value = '';
choice1Select.innerHTML = 'Select choice ';
choice2Select.innerHTML = 'Select choice ';
showNotification('Directive added successfully', 'success');
loadDirectives();
} else {
throw new Error(data.message || 'Failed to add directive');
}
})
.catch(error => {
console.error('Error in submitDirective:', error);
showNotification('Failed to add directive: ' + error.message, 'error');
});
}
function handleDirectiveAction(id, action) {
console.log(`Handling ${action} action for directive:`, id);
fetch('integrity_check_handler.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `action=${action}_directive&directive_id=${id}`
})
.then(response => {
console.log(`${action} directive response status:`, response.status);
if (!response.ok) {
throw new Error(`Server error: ${response.status}`);
}
return response.text().then(text => {
console.log("Raw response:", text); // Log the raw response
try {
return JSON.parse(text);
} catch (e) {
console.error("JSON parse error:", e);
throw new Error("Invalid JSON response: " + text.substring(0, 100));
}
});
})
.then(data => {
console.log(`${action} directive data:`, data);
if (data.success) {
showNotification(`Directive ${action === 'approve' ? 'approved' : 'revoked'} successfully`, 'success');
loadDirectives(); // Reload the directives list
} else {
throw new Error(data.message || `Failed to ${action} directive`);
}
})
.catch(error => {
console.error(`Error in ${action} directive:`, error);
showNotification(error.message, 'error');
});
}
function deleteDirective(id) {
if (!confirm('Are you sure you want to delete this directive?')) {
return;
}
fetch('integrity_check_handler.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `action=delete_directive&directive_id=${id}`
})
.then(response => {
console.log("Delete directive response status:", response.status);
if (!response.ok) {
throw new Error(`Server error: ${response.status}`);
}
return response.text().then(text => {
console.log("Raw response:", text);
try {
return JSON.parse(text);
} catch (e) {
console.error("JSON parse error:", e);
throw new Error("Invalid JSON response: " + text.substring(0, 100));
}
});
})
.then(data => {
console.log("Delete directive data:", data);
if (data.success) {
showNotification('Directive deleted successfully', 'success');
loadDirectives();
} else {
throw new Error(data.message || 'Failed to delete directive');
}
})
.catch(error => {
console.error('Error in deleteDirective:', error);
showNotification(error.message, 'error');
});
}
// Load choices for the selected attribute
function loadAttributeChoices(attributeId, targetSelectId) {
if (!attributeId) {
document.getElementById(targetSelectId).innerHTML = 'Select choice ';
return;
}
fetch('get_attribute_choices.php?attribute_id=' + attributeId)
.then(response => response.json())
.then(data => {
if (data.success) {
const select = document.getElementById(targetSelectId);
select.innerHTML = 'Select choice ';
data.choices.forEach(choice => {
const option = document.createElement('option');
option.value = choice;
option.textContent = choice;
select.appendChild(option);
});
} else {
console.error('Error loading choices:', data.message);
showNotification('Error loading choices: ' + data.message, 'error');
}
})
.catch(error => {
console.error('Error:', error);
showNotification('Error loading choices', 'error');
});
}
// Helper Functions
function switchTab(tab) {
console.log("Switching to tab:", tab);
// Find the tab elements
const tabs = document.querySelectorAll('.optimaize-tab');
const contents = document.querySelectorAll('.optimaize-content');
// Deactivate all tabs
tabs.forEach(t => t.classList.remove('active'));
contents.forEach(c => c.style.display = 'none');
// Activate the requested tab
let tabElement = null;
for (const t of tabs) {
if (t.getAttribute('data-tab') === tab ||
t.textContent.toLowerCase().includes(tab.toLowerCase())) {
tabElement = t;
break;
}
}
if (tabElement) {
tabElement.classList.add('active');
}
// Show the corresponding content
let contentElement = null;
if (tab === 'directives') {
contentElement = document.getElementById('directivesContent');
}
if (contentElement) {
contentElement.style.display = 'block';
// Load directives when switching to that tab
if (tab === 'directives') {
loadDirectives();
}
}
}
// Utility function to show notifications
function showNotification(message, type = 'success') {
console.log(`Notification (${type}):`, message);
const container = document.getElementById('notificationContainer');
if (!container) {
// Create container if it doesn't exist
const newContainer = document.createElement('div');
newContainer.id = 'notificationContainer';
newContainer.style.position = 'fixed';
newContainer.style.top = '20px';
newContainer.style.right = '20px';
newContainer.style.zIndex = '9999';
document.body.appendChild(newContainer);
// Use the newly created container
showNotification(message, type);
return;
}
const notification = document.createElement('div');
notification.className = `notification notification-${type}`;
notification.style.padding = '10px 15px';
notification.style.margin = '0 0 10px 0';
notification.style.borderRadius = '4px';
notification.style.boxShadow = '0 2px 5px rgba(0,0,0,0.2)';
notification.style.opacity = '0';
notification.style.transition = 'opacity 0.3s';
// Set background color based on type
if (type === 'success') {
notification.style.backgroundColor = '#4CAF50';
notification.style.color = 'white';
} else if (type === 'error') {
notification.style.backgroundColor = '#F44336';
notification.style.color = 'white';
} else if (type === 'warning') {
notification.style.backgroundColor = '#FF9800';
notification.style.color = 'white';
} else if (type === 'info') {
notification.style.backgroundColor = '#2196F3';
notification.style.color = 'white';
}
const icon = document.createElement('span');
icon.className = 'notification-icon';
icon.style.marginRight = '10px';
icon.textContent = type === 'success' ? '✓' : type === 'warning' ? '⚠' : type === 'info' ? 'ℹ' : '⨉';
const text = document.createElement('span');
text.className = 'notification-message';
text.textContent = message;
notification.appendChild(icon);
notification.appendChild(text);
container.appendChild(notification);
// Show notification with a small delay
setTimeout(() => {
notification.style.opacity = '1';
}, 10);
// Hide and remove after 5 seconds
setTimeout(() => {
notification.style.opacity = '0';
setTimeout(() => notification.remove(), 300);
}, 5000);
}
// Initialize event handlers
document.addEventListener('DOMContentLoaded', function() {
console.log("DOM loaded, initializing directive handlers");
// Setup tabs
const directivesTab = document.querySelector('.optimaize-tab[data-tab="directives"]');
if (directivesTab) {
directivesTab.addEventListener('click', (e) => {
console.log("Directives tab clicked");
e.preventDefault();
switchTab('directives');
});
console.log("Directives tab handler attached");
} else {
console.warn("Directives tab not found");
}
// Setup attribute selection change handlers
const attribute1Select = document.getElementById('attribute1');
const attribute2Select = document.getElementById('attribute2');
if (attribute1Select) {
attribute1Select.addEventListener('change', function() {
loadAttributeChoices(this.value, 'choice1');
});
}
if (attribute2Select) {
attribute2Select.addEventListener('change', function() {
loadAttributeChoices(this.value, 'choice2');
});
}
// Load directives by default
if (document.querySelector('.optimaize-section') &&
document.querySelector('.optimaize-section').style.display === 'block') {
console.log("Loading directives by default");
loadDirectives();
}
console.log("Directive initialization complete");
});
})();