// renderer.js document.addEventListener('DOMContentLoaded', () => { console.log('DOM fully loaded. renderer.js is now running.'); // --- 0. INITIALIZE FORM DEFAULTS --- const publicationDateInput = document.getElementById('publicationDate'); if (publicationDateInput) { publicationDateInput.value = new Date().toISOString().split('T')[0]; } // --- 1. TAB SWITCHING LOGIC --- const tabButtons = document.querySelectorAll('.tab-btn'); const tabContents = document.querySelectorAll('.tab-content'); tabButtons.forEach(button => { button.addEventListener('click', () => { tabButtons.forEach(btn => btn.classList.remove('active')); tabContents.forEach(content => content.classList.remove('active')); button.classList.add('active'); document.getElementById(button.dataset.tab + '-tab').classList.add('active'); }); }); document.getElementById('machine-tab').classList.add('active'); // --- 2. GENERIC DYNAMIC TABLE LOGIC --- function setupDynamicTable({ tableBodyId, templateId, bulkInputId, bulkBtnId, fields, // Array of field names in order (e.g. ['alarm_id', 'alarm_name', 'alarm_message']) prefix, // e.g. 'ALARM' nameFormat, // e.g. (id, paddedId) => `ALARM_${paddedId}` }) { const tableBody = document.getElementById(tableBodyId); const rowTemplate = document.getElementById(templateId); const bulkInput = bulkInputId ? document.getElementById(bulkInputId) : null; const bulkBtn = bulkBtnId ? document.getElementById(bulkBtnId) : null; // Add initial row addRow(tableBody, rowTemplate, 1, fields, prefix, nameFormat); // Bulk add if (bulkBtn && bulkInput) { bulkBtn.addEventListener('click', () => { let count = parseInt(bulkInput.value, 10); if (isNaN(count) || count < 1) count = 1; const currentIdInputs = tableBody.querySelectorAll(`[name="${fields[0]}"]`); let maxId = 0; currentIdInputs.forEach(input => { const currentId = parseInt(input.value, 10); if (!isNaN(currentId) && currentId > maxId) maxId = currentId; }); for (let i = 1; i <= count; i++) { addRow(tableBody, rowTemplate, maxId + i, fields, prefix, nameFormat); } }); } // Paste from Excel tableBody.addEventListener('paste', (event) => { const targetCell = event.target.closest('td'); const targetRow = event.target.closest('tr'); const allRows = Array.from(tableBody.querySelectorAll('tr')); let startRowIdx = allRows.indexOf(targetRow); if (startRowIdx === -1) startRowIdx = allRows.length; // Find the cell index in the row let startCellIdx = 0; if (targetCell && targetRow) { const cells = Array.from(targetRow.children); startCellIdx = cells.indexOf(targetCell); if (startCellIdx === -1) startCellIdx = 0; } // Get clipboard data const clipboardData = event.clipboardData || window.clipboardData; const pastedData = clipboardData.getData('Text'); if (!pastedData) return; // Find current max ID for auto-increment const currentIdInputs = tableBody.querySelectorAll(`[name="${fields[0]}"]`); let maxId = 0; currentIdInputs.forEach(input => { const currentId = parseInt(input.value, 10); if (!isNaN(currentId) && currentId > maxId) maxId = currentId; }); // Split rows by newline, columns by tab const rows = pastedData.trim().split(/\r?\n/); rows.forEach((row, rowOffset) => { const cols = row.split('\t'); if (cols.every(col => !col.trim())) return; // Ignore empty rows let rowToFill = allRows[startRowIdx + rowOffset]; if (!rowToFill) { // Add new row if needed maxId += 1; rowToFill = addRow(tableBody, rowTemplate, maxId, fields, prefix, nameFormat); } // Get all editable fields in the row const editableFields = fields.map(f => rowToFill.querySelector(`[name="${f}"]`)); // If only last field (description/message) is pasted, auto-fill ID and name if (cols.length === 1 || (cols.length > 0 && cols.slice(0, -1).every(col => !col.trim()))) { maxId += (!rowToFill.querySelector(`[name="${fields[0]}"]`).value ? 1 : 0); const paddedId = maxId.toString().padStart(3, '0'); if (editableFields[0]) editableFields[0].value = maxId; if (editableFields[1] && nameFormat) editableFields[1].value = nameFormat(maxId, paddedId); if (editableFields[editableFields.length - 1]) editableFields[editableFields.length - 1].value = cols[cols.length - 1].trim(); } else { // Paste values to the right, only filling available cells for (let colOffset = 0; colOffset < cols.length; colOffset++) { const fieldIdx = startCellIdx + colOffset; if (fieldIdx < editableFields.length && editableFields[fieldIdx]) { editableFields[fieldIdx].value = cols[colOffset].trim(); } } } }); event.preventDefault(); // Prevent default paste }); } function addRow(tableBody, rowTemplate, id, fields, prefix, nameFormat) { const paddedId = id.toString().padStart(3, '0'); const clone = rowTemplate.content.cloneNode(true); if (fields[0]) clone.querySelector(`[name="${fields[0]}"]`).value = id; if (fields[1] && nameFormat) clone.querySelector(`[name="${fields[1]}"]`).value = nameFormat(id, paddedId); const removeBtn = clone.querySelector('.remove-row-btn'); if (removeBtn) { removeBtn.addEventListener('click', (e) => { e.target.closest('tr').remove(); }); } tableBody.appendChild(clone); return tableBody.querySelectorAll('tr')[tableBody.querySelectorAll('tr').length - 1]; } // --- ALARMS --- setupDynamicTable({ tableBodyId: 'alarms-table-body', templateId: 'alarm-row-template', bulkInputId: 'bulk-alarm-count', bulkBtnId: 'add-multiple-alarms-btn', fields: ['alarm_id', 'alarm_name', 'alarm_message'], prefix: 'ALARM', nameFormat: (id, paddedId) => `ALARM_${paddedId}` }); // --- WARNINGS --- setupDynamicTable({ tableBodyId: 'warnings-table-body', templateId: 'warning-row-template', bulkInputId: 'bulk-warning-count', bulkBtnId: 'add-multiple-warnings-btn', fields: ['warning_id', 'warning_name', 'warning_message'], prefix: 'WARNING', nameFormat: (id, paddedId) => `WARNING_${paddedId}` }); // --- COUNTERS --- setupDynamicTable({ tableBodyId: 'counters-table-body', templateId: 'counter-row-template', bulkInputId: null, // Add bulk if you want bulkBtnId: null, // Add bulk if you want fields: ['counter_id', 'counter_name', 'counter_type', 'counter_description'], prefix: 'COUNTER', nameFormat: (id, paddedId) => `COUNTER_${paddedId}` }); // --- SETPOINTS --- setupDynamicTable({ tableBodyId: 'setpoints-table-body', templateId: 'setpoint-row-template', bulkInputId: null, // Add bulk if you want bulkBtnId: null, // Add bulk if you want fields: ['setpoint_id', 'setpoint_name', 'setpoint_message'], prefix: 'SETPOINT', nameFormat: (id, paddedId) => `SETPOINT_${paddedId}` }); // --- REALTIME VARIABLES --- setupDynamicTable({ tableBodyId: 'realtime-table-body', templateId: 'realtime-row-template', bulkInputId: null, // Add bulk if you want bulkBtnId: null, // Add bulk if you want fields: ['realtime_id', 'realtime_name', 'realtime_message'], prefix: 'REALTIME', nameFormat: (id, paddedId) => `REALTIME_${paddedId}` }); // --- 3. FORM SUBMISSION LOGIC --- const form = document.getElementById('machine-form'); if (form) { form.addEventListener('submit', async (event) => { event.preventDefault(); // A. Collect data from the main "Machine" tab using FormData const formData = new FormData(form); // Convert FormData to a plain object const mainData = {}; for (const [key, value] of formData.entries()) { // This check prevents multi-value fields from overwriting themselves if (!mainData[key]) { mainData[key] = value; } } mainData.addins = formData.getAll('addins'); // B. Collect all alarm rows from the table const alarmRows = alarmsTableBody.querySelectorAll('tr'); const alarmsData = []; alarmRows.forEach(row => { const alarm = { id: row.querySelector('[name="alarm_id"]').value, name: row.querySelector('[name="alarm_name"]').value, message: row.querySelector('[name="alarm_message"]').value, }; if (alarm.message) { alarmsData.push(alarm); } }); // D. Collect all warning rows from the table const warningRows = warningsTableBody.querySelectorAll('tr'); const warningsData = []; warningRows.forEach(row => { const warning = { id: row.querySelector('[name="warning_id"]').value, name: row.querySelector('[name="warning_name"]').value, message: row.querySelector('[name="warning_message"]').value, }; if (warning.message) { warningsData.push(warning); } }); // E. Collect all counter rows from the table const counterRows = countersTableBody.querySelectorAll('tr'); const countersData = []; counterRows.forEach(row => { const counter = { id: row.querySelector('[name="counter_id"]').value, name: row.querySelector('[name="counter_name"]').value, type: row.querySelector('[name="counter_type"]').value, description: row.querySelector('[name="counter_description"]').value, }; if (counter.type) { countersData.push(counter); } }); // C. Combine all data into a single object const finalData = { ...mainData, alarms: alarmsData, warnings: warningsData, counters: countersData }; console.log('Sending all collected data to main process:', finalData); try { const result = await window.electronAPI.submitForm(finalData); if (result.success) { // // Reset the entire form to its initial state // form.reset(); // // Re-apply the defaults that are not part of the standard reset // document.getElementById('publicationDate').value = new Date().toISOString().split('T')[0]; // document.querySelector('#stopReasonYes').checked = true; // Set StopReason back to Yes // updateFilename(); // Clear the filename preview } } catch (error) { console.error('Error during form submission process:', error); } }); } // --- 4. TAB NAVIGATION BUTTONS --- const tabOrder = [ 'machine-tab', 'alarms-tab', 'warnings-tab', 'counters-tab', 'setpoints-tab', 'realtime-tab' ]; // Add event listeners to all "Next" buttons document.querySelectorAll('.next-tab-btn').forEach((btn, idx) => { btn.addEventListener('click', () => { // Find the currently active tab const currentTab = document.querySelector('.tab-content.active'); if (!currentTab) return; const currentTabId = currentTab.id; const currentIdx = tabOrder.indexOf(currentTabId); const nextTabId = tabOrder[currentIdx + 1]; if (nextTabId) { // Switch tab button active state document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active')); document.querySelector(`[data-tab="${nextTabId.replace('-tab','')}"]`).classList.add('active'); // Switch tab content active state document.querySelectorAll('.tab-content').forEach(tc => tc.classList.remove('active')); document.getElementById(nextTabId).classList.add('active'); } }); }); });