PixelPlacerBot/resources/js/palette-editor.js
2024-07-28 18:06:05 -04:00

456 lines
18 KiB
JavaScript

document.addEventListener('DOMContentLoaded', function() {
console.log('DOM fully loaded and parsed.');
const paletteSelector = document.getElementById('palette-selector');
const newPaletteButton = document.getElementById('new-palette');
const newPaletteForm = document.getElementById('new-palette-form');
const createPaletteForm = document.getElementById('create-palette-form');
const addColorForm = document.getElementById('add-color-form');
const createColorForm = document.getElementById('create-color-form');
const colorEditorsDiv = document.getElementById('color-editors');
const addColorButton = document.getElementById('add-color');
const savePaletteButton = document.getElementById('save-palette');
const exportPaletteButton = document.getElementById('export-palette');
const importPaletteButton = document.getElementById('import-palette');
const importFileInput = document.getElementById('import-file');
const renamePaletteButton = document.getElementById('rename-palette');
const renamePaletteNameInput = document.getElementById('rename-palette-name');
const deletePaletteButton = document.getElementById('delete-palette');
const deleteModal = new bootstrap.Modal(document.getElementById('deleteModal'), {});
const confirmDeleteCheckbox = document.getElementById('confirmDeleteCheckbox');
const confirmDeleteButton = document.getElementById('confirmDeleteButton');
// CSRF token
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
// Logging element states
console.log('paletteSelector:', paletteSelector);
console.log('newPaletteButton:', newPaletteButton);
console.log('newPaletteForm:', newPaletteForm);
console.log('createPaletteForm:', createPaletteForm);
console.log('addColorForm:', addColorForm);
console.log('createColorForm:', createColorForm);
console.log('colorEditorsDiv:', colorEditorsDiv);
console.log('addColorButton:', addColorButton);
console.log('savePaletteButton:', savePaletteButton);
console.log('deletePaletteButton:', deletePaletteButton);
console.log('csrfToken:', csrfToken);
if (!paletteSelector || !newPaletteButton || !newPaletteForm || !createPaletteForm || !addColorForm || !createColorForm || !colorEditorsDiv || !addColorButton || !savePaletteButton || !exportPaletteButton || !importPaletteButton || !importFileInput || !renamePaletteButton || !renamePaletteNameInput || !deletePaletteButton) {
console.error('Missing required elements on the page.');
return;
}
newPaletteButton.addEventListener('click', function() {
newPaletteForm.style.display = 'block';
});
createPaletteForm.addEventListener('submit', function(event) {
event.preventDefault();
const formData = new FormData(createPaletteForm);
console.log('Creating new palette with data:', formData);
fetch('/palette-editor', {
method: 'POST',
body: formData,
headers: {
'X-CSRF-TOKEN': csrfToken
}
})
.then(response => response.json())
.then(data => {
console.log('Palette created:', data);
fetchPalettes().then(() => {
const newOption = document.createElement('option');
newOption.value = data.id;
newOption.text = data.name;
paletteSelector.add(newOption);
paletteSelector.value = data.id;
loadPaletteColors(data.id);
});
newPaletteForm.style.display = 'none';
createPaletteForm.reset();
})
.catch(error => {
console.error('Error creating palette:', error);
});
});
paletteSelector.addEventListener('change', function() {
const paletteId = paletteSelector.value;
console.log('Palette selected:', paletteId);
if (paletteId) {
loadPaletteColors(paletteId);
checkPaletteRestrictions();
} else {
addColorForm.style.display = 'none';
colorEditorsDiv.innerHTML = '';
}
});
addColorButton.addEventListener('click', function() {
addColorEditor();
});
savePaletteButton.addEventListener('click', function() {
const paletteId = createColorForm.getAttribute('data-palette-id');
const colorEditors = document.querySelectorAll('.color-editor');
const colorUpdates = [];
colorEditors.forEach(editor => {
const colorId = editor.getAttribute('data-color-id');
const colorName = editor.querySelector('.color-name').value;
const colorHex = editor.querySelector('.color-hex-input').value;
colorUpdates.push({
colorId,
colorName,
colorHex
});
});
console.log('Saving palette with ID:', paletteId);
colorUpdates.forEach(({colorId, colorName, colorHex}) => {
console.log(`Saving color: ${colorName} (${colorHex}) with ID: ${colorId}`);
if (colorId) {
// Update existing color
fetch(`/palette-editor/${paletteId}/colors/${colorId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': csrfToken
},
body: JSON.stringify({ name: colorName, hex_value: colorHex })
})
.then(response => response.json())
.then(data => {
console.log('Color updated:', data);
})
.catch(error => {
console.error('Error updating color:', error);
});
} else {
// Add new color
fetch(`/palette-editor/${paletteId}/colors`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': csrfToken
},
body: JSON.stringify({ name: colorName, hex_value: colorHex })
})
.then(response => response.json())
.then(data => {
console.log('Color added:', data);
editor.setAttribute('data-color-id', data.id);
})
.catch(error => {
console.error('Error adding color:', error);
});
}
});
});
exportPaletteButton.addEventListener('click', function() {
const paletteId = paletteSelector.value;
console.log('Exporting palette with ID:', paletteId);
if (paletteId) {
fetch(`/palette-editor/${paletteId}/export`)
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.blob();
})
.then(blob => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.style.display = 'none';
a.href = url;
a.download = `${paletteSelector.options[paletteSelector.selectedIndex].text}.pal`;
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
})
.catch(error => {
console.error('Error exporting palette:', error);
});
} else {
alert('Please select a palette to export.');
}
});
importPaletteButton.addEventListener('click', function() {
importFileInput.click();
});
importFileInput.addEventListener('change', function(event) {
const file = event.target.files[0];
if (file) {
const formData = new FormData();
formData.append('file', file);
console.log('Importing palette from file:', file.name);
fetch('/palette-editor/import', {
method: 'POST',
body: formData,
headers: {
'X-CSRF-TOKEN': csrfToken
}
})
.then(response => response.json())
.then(data => {
console.log('Palette imported successfully', data);
const newOption = document.createElement('option');
newOption.value = data.palette.id;
newOption.text = data.palette.name;
paletteSelector.add(newOption);
paletteSelector.value = data.palette.id;
loadPaletteColors(data.palette.id);
})
.catch(error => {
console.error('Error importing palette:', error);
});
}
});
renamePaletteButton.addEventListener('click', function() {
const paletteId = paletteSelector.value;
const newName = renamePaletteNameInput.value.trim();
console.log('Renaming palette ID:', paletteId, 'to:', newName);
if (!paletteId) {
alert('Please select a palette to rename.');
return;
}
if (!newName) {
alert('Please enter a new name for the palette.');
return;
}
fetch(`/palette-editor/${paletteId}/rename`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': csrfToken
},
body: JSON.stringify({ name: newName })
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => {
console.log('Palette renamed:', data);
fetchPalettes().then(() => {
const option = Array.from(paletteSelector.options).find(option => option.value == paletteId);
if (option) {
option.text = newName;
paletteSelector.value = paletteId;
}
loadPaletteColors(paletteId);
});
})
.catch(error => {
console.error('Error renaming palette:', error);
});
});
deletePaletteButton.addEventListener('click', function() {
const paletteId = paletteSelector.value;
console.log('Preparing to delete palette ID:', paletteId);
if (!paletteId) {
alert('Please select a palette to delete.');
return;
}
// Show modal
deleteModal.show();
});
confirmDeleteCheckbox.addEventListener('change', function() {
confirmDeleteButton.disabled = !confirmDeleteCheckbox.checked;
});
confirmDeleteButton.addEventListener('click', function() {
const paletteId = paletteSelector.value;
console.log('Deleting palette with ID:', paletteId);
if (paletteId && confirmDeleteCheckbox.checked) {
fetch(`/palette-editor/${paletteId}`, {
method: 'DELETE',
headers: {
'X-CSRF-TOKEN': csrfToken
}
})
.then(response => response.json())
.then(data => {
console.log('Palette deleted:', data);
fetchPalettes().then(() => {
const option = Array.from(paletteSelector.options).find(option => option.value == paletteId);
if (option) {
paletteSelector.removeChild(option);
}
const defaultPaletteOption = Array.from(paletteSelector.options).find(option => option.text === 'default-colors');
if (defaultPaletteOption) {
defaultPaletteOption.selected = true;
loadPaletteColors(defaultPaletteOption.value);
} else {
paletteSelector.value = '';
colorEditorsDiv.innerHTML = '';
}
});
deleteModal.hide();
})
.catch(error => {
console.error('Error deleting palette:', error);
});
}
});
function loadPaletteColors(paletteId) {
console.log('Loading colors for palette ID:', paletteId);
fetch(`/palette-editor/${paletteId}/colors`)
.then(response => response.json())
.then(data => {
console.log('Loaded palette colors:', data);
colorEditorsDiv.innerHTML = '';
data.forEach(color => {
addColorEditor(color.id, color.name, color.hex_value);
});
addColorForm.style.display = 'block';
createColorForm.setAttribute('data-palette-id', paletteId);
})
.catch(error => {
console.error('Error loading palette colors:', error);
});
}
function addColorEditor(colorId = '', colorName = '', colorHex = '#ffffff') {
console.log(`Adding color editor for color: ${colorName} (${colorHex}) with ID: ${colorId}`);
const editor = document.createElement('div');
editor.className = 'color-editor col-md-2 mb-3';
editor.setAttribute('data-color-id', colorId);
editor.innerHTML = `
<div class="form-row align-items-end">
<div class="col-12">
<label>Color Name:</label>
<input type="text" class="form-control color-name" value="${colorName}" required>
</div>
<div class="col-12">
<label>Color Hex:</label>
<div class="color-picker"></div>
<input type="hidden" class="color-hex-input" value="${colorHex}" required>
</div>
<div class="col-12 text-right mt-2">
<button type="button" class="btn btn-danger btn-sm delete-color"><i class="fas fa-trash-alt"></i></button>
</div>
</div>
`;
colorEditorsDiv.appendChild(editor);
const deleteButton = editor.querySelector('.delete-color');
deleteButton.addEventListener('click', function() {
const paletteId = createColorForm.getAttribute('data-palette-id');
if (paletteId === '1') {
alert('Cannot delete colors from the default-colors palette.');
return;
}
console.log('Deleting color ID:', colorId, 'from palette ID:', paletteId);
if (colorId) {
fetch(`/palette-editor/${paletteId}/colors/${colorId}`, {
method: 'DELETE',
headers: {
'X-CSRF-TOKEN': csrfToken
}
})
.then(response => response.json())
.then(data => {
console.log('Color deleted:', data.message);
colorEditorsDiv.removeChild(editor);
})
.catch(error => {
console.error('Error deleting color:', error);
});
} else {
colorEditorsDiv.removeChild(editor);
}
});
const pickr = Pickr.create({
el: editor.querySelector('.color-picker'),
theme: 'classic', // or 'monolith', or 'nano'
default: colorHex,
components: {
preview: true,
opacity: false,
hue: true,
interaction: {
hex: true,
input: true,
clear: true,
save: true
}
}
});
pickr.on('save', (color, instance) => {
editor.querySelector('.color-hex-input').value = color.toHEXA().toString();
pickr.hide();
});
pickr.on('clear', instance => {
editor.querySelector('.color-hex-input').value = '';
});
}
function fetchPalettes() {
console.log('Fetching palettes from the server');
return fetch('/palette-editor')
.then(response => response.json())
.then(data => {
console.log('Fetched palettes:', data);
paletteSelector.innerHTML = '';
data.forEach(palette => {
const option = document.createElement('option');
option.value = palette.id;
option.text = palette.name;
paletteSelector.add(option);
});
})
.catch(error => {
console.error('Error fetching palettes:', error);
});
}
function checkPaletteRestrictions() {
const paletteId = paletteSelector.value;
const isDefaultPalette = paletteId === '1';
console.log('Checking restrictions for palette ID:', paletteId, 'isDefaultPalette:', isDefaultPalette);
deletePaletteButton.disabled = isDefaultPalette;
addColorButton.disabled = isDefaultPalette;
savePaletteButton.disabled = isDefaultPalette;
if (isDefaultPalette) {
document.querySelectorAll('.delete-color').forEach(button => {
button.disabled = true;
});
} else {
document.querySelectorAll('.delete-color').forEach(button => {
button.disabled = false;
});
}
}
// Load default colors on page load
window.onload = function() {
console.log('Page loaded, selecting default palette if available');
const defaultPaletteOption = Array.from(paletteSelector.options).find(option => option.text === 'default-colors');
if (defaultPaletteOption) {
defaultPaletteOption.selected = true;
loadPaletteColors(defaultPaletteOption.value);
}
};
});