diff --git a/src/registrar/assets/src/js/getgov/form-nameservers.js b/src/registrar/assets/src/js/getgov/form-nameservers.js index 6b425625a..fc67d3edc 100644 --- a/src/registrar/assets/src/js/getgov/form-nameservers.js +++ b/src/registrar/assets/src/js/getgov/form-nameservers.js @@ -4,6 +4,7 @@ export class NameserverForm { constructor() { this.addNameserverButton = document.getElementById('nameserver-add-form'); this.nameserversForm = document.querySelector('.nameservers-form'); + this.formChanged = false; // Bind event handlers to maintain 'this' context this.handleAddFormClick = this.handleAddFormClick.bind(this); @@ -28,6 +29,20 @@ export class NameserverForm { showElement(this.nameserversForm); hideElement(this.addNameserverButton); } + + // handle display of table view errors + // if error exists in an edit-row, make that row show, and readonly row hide + const formTable = document.querySelector('.usa-table') + if (formTable) { + const editRows = formTable.querySelectorAll('.edit-row'); + editRows.forEach(editRow => { + if (editRow.querySelector('.usa-input--error')) { + const readOnlyRow = editRow.previousElementSibling; + showElement(editRow); + hideElement(readOnlyRow); + } + }) + } } initializeEventListeners() { @@ -42,6 +57,14 @@ export class NameserverForm { cancelButtons.forEach(cancelButton => { cancelButton.addEventListener('click', this.handleCancelClick); }); + + const textInputs = document.querySelectorAll("input[type='text']"); + textInputs.forEach(input => { + input.addEventListener("input", function() { + this.formChanged = true; + console.log("Form changed"); + }) + }) } handleAddFormClick(event) { @@ -53,37 +76,117 @@ export class NameserverForm { let editButton = event.target; let readOnlyRow = editButton.closest('tr'); // Find the closest row let editRow = readOnlyRow.nextElementSibling; // Get the next row - if (!editRow || !readOnlyRow) { console.warn("Expected DOM element but did not find it"); return; } - // Check if any other edit row is currently visible and hide it document.querySelectorAll('tr.edit-row:not(.display-none)').forEach(openEditRow => { let correspondingReadOnlyRow = openEditRow.previousElementSibling; hideElement(openEditRow); showElement(correspondingReadOnlyRow); }); - + // hide and show rows as appropriate hideElement(readOnlyRow); showElement(editRow); } + /** + * Handles the click event for the cancel button within the table form. + * + * This method identifies the edit row containing the cancel button and resets + * it to its initial state, restoring the corresponding read-only row. + * + * @param {Event} event - the click event triggered by the cancel button + */ handleCancelClick(event) { + // get the cancel button that was clicked let cancelButton = event.target; - let editRow = cancelButton.closest('tr'); // Find the closest row - let readOnlyRow = editRow.previousElementSibling; // Get the next row + // find the closest table row that contains the cancel button + let editRow = cancelButton.closest('tr'); + if (editRow) { + this.resetEditRowAndFormAndCollapseEditRow(editRow); + } else { + console.warn("Expected DOM element but did not find it"); + } + } + resetEditRowAndFormAndCollapseEditRow(editRow) { + let readOnlyRow = editRow.previousElementSibling; // Get the next row if (!editRow || !readOnlyRow) { console.warn("Expected DOM element but did not find it"); return; } - + // reset the values set in editRow + this.resetInputValuesInRow(editRow); + // copy values from editRow to readOnlyRow + this.copyEditRowToReadonlyRow(editRow, readOnlyRow); + // remove errors from the editRow + this.removeErrorsFromRow(editRow); + // remove errors from the entire form + this.removeFormErrors(); + // reset formChanged + this.resetFormChanged(); + // hide and show rows as appropriate hideElement(editRow); showElement(readOnlyRow); } + resetInputValuesInRow(editRow) { + let textInputs = editRow.querySelectorAll("input[type='text']"); + textInputs.forEach(input => { + input.value = input.dataset.initialValue; + }) + } + + copyEditRowToReadonlyRow(editRow, readOnlyRow) { + let textInputs = editRow.querySelectorAll("input[type='text']"); + let tds = readOnlyRow.querySelectorAll("td"); + + // if server is defined, copy the value to the first td in readOnlyRow + if (textInputs[0] && tds[0]) { + tds[0].innerText = textInputs[0].value; + } + + // if ip is defined, copy the value to the second td in readOnlyRow + if (textInputs[1] && tds[1]) { + tds[1].innerText = textInputs[1].value; + } + } + + removeErrorsFromRow(editRow) { + // remove class 'usa-form-group--error' from divs in editRow + editRow.querySelectorAll("div.usa-form-group--error").forEach(div => { + div.classList.remove("usa-form-group--error"); + }); + + // remove class 'usa-label--error' from labels in editRow + editRow.querySelectorAll("label.usa-label--error").forEach(label => { + label.classList.remove("usa-label--error"); + }); + + // Remove divs whose id ends with '__error-message' (error message divs) + editRow.querySelectorAll("div[id$='__error-message']").forEach(errorDiv => { + errorDiv.remove(); + }); + + // remove class 'usa-input--error' from inputs in editRow + editRow.querySelectorAll("input.usa-input--error").forEach(input => { + input.classList.remove("usa-input--error"); + }); + } + + removeFormErrors() { + let formErrorDiv = document.getElementById("form-errors"); + if (formErrorDiv) { + formErrorDiv.remove(); + } + } + + resetFormChanged() { + this.formChanged = false; + } + } export function initFormNameservers() { diff --git a/src/registrar/templates/domain_nameservers.html b/src/registrar/templates/domain_nameservers.html index 856f4f62c..d547378df 100644 --- a/src/registrar/templates/domain_nameservers.html +++ b/src/registrar/templates/domain_nameservers.html @@ -62,13 +62,13 @@