`;
fpiLogList.appendChild(item);
});
}
}
function renderAllConfigLists() {
Object.keys(fpiDropdownData).forEach(renderConfigList);
}
function renderConfigList(type) {
const listEl = fpiToolContainer.querySelector(`#fpi-list-${type}`);
if (!listEl) return;
listEl.innerHTML = ''; // Clear
fpiDropdownData[type].forEach(option => {
const tag = document.createElement('div');
tag.className = 'fpi-config-tag';
tag.innerHTML = `
${option}
`;
listEl.appendChild(tag);
});
}
function renderAllDashboardDropdowns() {
Object.keys(fpiDropdownData).forEach(renderDashboardDropdown);
}
function renderDashboardDropdown(type) {
const selectEl = fpiToolContainer.querySelector(`#fpi-select-${type}`);
if (!selectEl) return;
selectEl.innerHTML = '';
fpiDropdownData[type].forEach(option => {
const optionEl = document.createElement('option');
optionEl.value = option;
optionEl.textContent = option;
selectEl.appendChild(optionEl);
});
}
// --- Event Handlers ---
function handleAddInk(e) {
e.preventDefault();
const newInk = {
id: fpiNextId++,
name: fpiToolContainer.querySelector('#fpi-input-name').value,
brand: fpiToolContainer.querySelector('#fpi-input-brand').value,
pen: fpiToolContainer.querySelector('#fpi-input-pen').value,
color: fpiToolContainer.querySelector('#fpi-input-color').value,
flow: fpiToolContainer.querySelector('#fpi-select-flow').value,
shading: fpiToolContainer.querySelector('#fpi-select-shading').value,
sheen: fpiToolContainer.querySelector('#fpi-select-sheen').value,
notes: fpiToolContainer.querySelector('#fpi-textarea-notes').value
};
fpiInkLog.push(newInk);
renderLogList();
fpiAddForm.reset();
fpiToolContainer.querySelector('#fpi-input-color').value = '#005bb5'; // Reset color
}
function handleLogListClick(e) {
const target = e.target;
if (target.matches('.fpi-delete-btn')) {
const id = parseInt(target.dataset.id, 10);
if (confirm("Are you sure you want to delete this ink log?")) {
fpiInkLog = fpiInkLog.filter(ink => ink.id !== id);
renderLogList();
}
}
if (target.matches('.fpi-edit-btn')) {
const id = parseInt(target.dataset.id, 10);
const ink = fpiInkLog.find(ink => ink.id === id);
if (!ink) return;
// Use prompt() for simple editing as alert/confirm are banned, but prompt is okay.
const newName = prompt("Edit Ink Name:", ink.name);
if (newName === null) return;
const newBrand = prompt("Edit Ink Brand:", ink.brand);
if (newBrand === null) return;
const newPen = prompt("Edit Pen Used:", ink.pen);
if (newPen === null) return;
const newNotes = prompt("Edit Notes:", ink.notes);
if (newNotes === null) return;
// Update the ink object
ink.name = newName;
ink.brand = newBrand;
ink.pen = newPen;
ink.notes = newNotes;
renderLogList();
}
}
function handleConfigClick(e) {
const target = e.target;
if (target.matches('.fpi-add-btn')) {
const type = target.dataset.type;
const input = fpiToolContainer.querySelector(`#fpi-input-${type}`);
if (input) {
const value = input.value.trim();
if (value && !fpiDropdownData[type].includes(value)) {
fpiDropdownData[type].push(value);
renderConfigList(type);
renderAllDashboardDropdowns();
input.value = '';
}
}
}
if (target.matches('.fpi-delete-btn')) {
const type = target.dataset.type;
const value = target.dataset.value;
fpiDropdownData[type] = fpiDropdownData[type].filter(opt => opt !== value);
renderConfigList(type);
renderAllDashboardDropdowns();
}
}
/** Saves label configuration */
window.fpiSaveConfig = function() {
for (const [configId, targetId] of Object.entries(fpiLabelMap)) {
const configInput = document.getElementById(configId);
const targetElement = document.getElementById(targetId);
if (configInput && targetElement) {
targetElement.textContent = configInput.value.trim() || "Label";
}
}
alert('Labels saved!');
fpiTabLinks[0].click(); // Switch to dashboard
}
/** Generates and downloads a PDF of the report */
async function downloadPDF() {
if (typeof jspdf === 'undefined' || typeof html2canvas === 'undefined') {
console.error("jsPDF or html2canvas library not loaded.");
alert("Error: PDF generation libraries not loaded.");
return;
}
const { jsPDF } = window.jspdf;
if (fpiPdfBtn) {
fpiPdfBtn.textContent = 'Generating...';
fpiPdfBtn.disabled = true;
}
const contentToExport = document.getElementById('fpi-pdf-content');
if (!contentToExport) {
// ... reset button
return;
}
contentToExport.classList.add('fpi-pdf-export-content');
try {
const canvas = await html2canvas(contentToExport, {
scale: 2,
useCORS: true,
logging: false,
onclone: (doc) => {
// Hide controls in the cloned document
doc.querySelectorAll('.fpi-pdf-hide-in-export').forEach(el => {
el.style.display = 'none';
});
}
});
const imgData = canvas.toDataURL('image/png');
const pdf = new jsPDF({ orientation: 'p', unit: 'px', format: 'a4' });
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = pdf.internal.pageSize.getHeight();
const ratio = canvas.width / pdfWidth;
const scaledHeight = canvas.height / ratio;
let position = 0;
let heightLeft = scaledHeight;
pdf.addImage(imgData, 'PNG', 0, position, pdfWidth, scaledHeight);
heightLeft -= pdfHeight;
while (heightLeft > 0) {
position = heightLeft - scaledHeight;
pdf.addPage();
pdf.addImage(imgData, 'PNG', 0, position, pdfWidth, scaledHeight);
heightLeft -= pdfHeight;
}
pdf.save('fountain_pen_ink_log.pdf');
} catch (error) {
console.error("Error during PDF generation:", error);
alert("An error occurred while generating the PDF.");
} finally {
// Clean up
contentToExport.classList.remove('fpi-pdf-export-content');
if (fpiPdfBtn) {
fpiPdfBtn.textContent = 'Download Log as PDF';
fpiPdfBtn.disabled = false;
}
}
}
// --- Tab Navigation Functions ---
window.fpiOpenTab = function(evt, tabName) {
if (!fpiTabContents.length || !fpiTabLinks.length) return;
fpiTabContents.forEach(tabcontent => {
tabcontent.style.display = "none";
tabcontent.classList.remove('fpi-active');
});
fpiTabLinks.forEach(tablink => {
tablink.classList.remove('fpi-active');
});
const currentTabContent = document.getElementById(tabName);
if (currentTabContent) {
currentTabContent.style.display = "block";
currentTabContent.classList.add('fpi-active');
}
if (evt && evt.currentTarget) {
evt.currentTarget.classList.add('fpi-active');
}
fpiCurrentTab = fpiTabLinks.indexOf(evt.currentTarget);
updateNavButtons();
}
window.fpiNavTab = function(n) {
const newIndex = fpiCurrentTab + n;
if (newIndex >= 0 && newIndex < fpiTabLinks.length) {
fpiTabLinks[newIndex].click();
}
}
function updateNavButtons() {
if (fpiPrevBtn) fpiPrevBtn.disabled = (fpiCurrentTab === 0);
if (fpiNextBtn) fpiNextBtn.disabled = (fpiCurrentTab === fpiTabLinks.length - 1);
}
})();
