mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-07-23 11:16:07 +02:00
commented code
This commit is contained in:
parent
4eec0aa0ef
commit
d7efec5db0
2 changed files with 151 additions and 33 deletions
|
@ -17,11 +17,19 @@ export class NameserverForm {
|
|||
this.handleCancelAddFormClick = this.handleCancelAddFormClick.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the NameserverForm by setting up display and event listeners.
|
||||
*/
|
||||
init() {
|
||||
this.initializeNameserverFormDisplay();
|
||||
this.initializeEventListeners();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determines the initial display state of the nameserver form,
|
||||
* handling validation errors and setting visibility of elements accordingly.
|
||||
*/
|
||||
initializeNameserverFormDisplay() {
|
||||
|
||||
const domainName = document.getElementById('id_form-0-domain');
|
||||
|
@ -76,9 +84,11 @@ export class NameserverForm {
|
|||
}
|
||||
formIndex++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches event listeners to relevant UI elements for interaction handling.
|
||||
*/
|
||||
initializeEventListeners() {
|
||||
this.addNameserverButton.addEventListener('click', this.handleAddFormClick);
|
||||
|
||||
|
@ -115,7 +125,8 @@ export class NameserverForm {
|
|||
});
|
||||
|
||||
// Add a specific listener for 'id_form-{number}-server' inputs to make
|
||||
// nameserver forms 'smart'
|
||||
// nameserver forms 'smart'. Inputs on server field will change the
|
||||
// display value of the associated IP address field.
|
||||
let formIndex = 0;
|
||||
while (document.getElementById(`id_form-${formIndex}-server`)) {
|
||||
let serverInput = document.getElementById(`id_form-${formIndex}-server`);
|
||||
|
@ -137,6 +148,9 @@ export class NameserverForm {
|
|||
formIndex++; // Move to the next index
|
||||
}
|
||||
|
||||
// Set event listeners on the submit buttons for the modals. Event listeners
|
||||
// should execute the callback function, which has its logic updated prior
|
||||
// to modal display
|
||||
const unsaved_changes_modal = document.getElementById('unsaved-changes-modal');
|
||||
if (unsaved_changes_modal) {
|
||||
const submitButton = document.getElementById('unsaved-changes-click-button');
|
||||
|
@ -146,7 +160,6 @@ export class NameserverForm {
|
|||
this.executeCallback();
|
||||
});
|
||||
}
|
||||
|
||||
const delete_modal = document.getElementById('delete-modal');
|
||||
if (delete_modal) {
|
||||
const submitButton = document.getElementById('delete-click-button');
|
||||
|
@ -159,6 +172,9 @@ export class NameserverForm {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a stored callback function if defined, otherwise logs a warning.
|
||||
*/
|
||||
executeCallback() {
|
||||
if (this.callback) {
|
||||
this.callback();
|
||||
|
@ -168,6 +184,10 @@ export class NameserverForm {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles clicking the 'Add Nameserver' button, showing the form if needed.
|
||||
* @param {Event} event - Click event
|
||||
*/
|
||||
handleAddFormClick(event) {
|
||||
this.callback = () => {
|
||||
// Check if any other edit row is currently visible and hide it
|
||||
|
@ -186,7 +206,7 @@ export class NameserverForm {
|
|||
}
|
||||
};
|
||||
if (this.formChanged) {
|
||||
//------- Show the confirmation modal
|
||||
//------- Show the unsaved changes confirmation modal
|
||||
let modalTrigger = document.querySelector("#unsaved_changes_trigger");
|
||||
if (modalTrigger) {
|
||||
modalTrigger.click();
|
||||
|
@ -196,6 +216,11 @@ export class NameserverForm {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles clicking an 'Edit' button on a readonly row, which hides the readonly row
|
||||
* and displays the edit row, after performing some checks and possibly displaying modal.
|
||||
* @param {Event} event - Click event
|
||||
*/
|
||||
handleEditClick(event) {
|
||||
let editButton = event.target;
|
||||
let readOnlyRow = editButton.closest('tr'); // Find the closest row
|
||||
|
@ -218,7 +243,7 @@ export class NameserverForm {
|
|||
showElement(editRow);
|
||||
};
|
||||
if (this.formChanged) {
|
||||
//------- Show the confirmation modal
|
||||
//------- Show the unsaved changes confirmation modal
|
||||
let modalTrigger = document.querySelector("#unsaved_changes_trigger");
|
||||
if (modalTrigger) {
|
||||
modalTrigger.click();
|
||||
|
@ -228,6 +253,11 @@ export class NameserverForm {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles clicking a 'Delete' button on an edit row, which hattempts to delete the nameserver
|
||||
* after displaying modal and performing check for minimum number of nameservers.
|
||||
* @param {Event} event - Click event
|
||||
*/
|
||||
handleDeleteClick(event) {
|
||||
let deleteButton = event.target;
|
||||
let editRow = deleteButton.closest('tr');
|
||||
|
@ -238,6 +268,11 @@ export class NameserverForm {
|
|||
this.deleteRow(editRow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles clicking a 'Delete' button on a readonly row in a kebab, which hattempts to delete the nameserver
|
||||
* after displaying modal and performing check for minimum number of nameservers.
|
||||
* @param {Event} event - Click event
|
||||
*/
|
||||
handleDeleteKebabClick(event) {
|
||||
let deleteKebabButton = event.target;
|
||||
let accordionDiv = deleteKebabButton.closest('div');
|
||||
|
@ -252,6 +287,12 @@ export class NameserverForm {
|
|||
this.deleteRow(editRow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a nameserver row after verifying the minimum required nameservers exist.
|
||||
* If there are only two nameservers left, deletion is prevented, and an alert is shown.
|
||||
* If deletion proceeds, the input fields are cleared, and the form is submitted.
|
||||
* @param {HTMLElement} editRow - The row corresponding to the nameserver being deleted.
|
||||
*/
|
||||
deleteRow(editRow) {
|
||||
// Check if at least two nameserver forms exist
|
||||
const fourthNameserver = document.getElementById('id_form-3-server'); // This should exist
|
||||
|
@ -273,6 +314,11 @@ export class NameserverForm {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the click event on the "Cancel" button in the add nameserver form.
|
||||
* Resets the form fields and hides the add form section.
|
||||
* @param {Event} event - Click event
|
||||
*/
|
||||
handleCancelAddFormClick(event) {
|
||||
this.resetAddNameserversForm();
|
||||
}
|
||||
|
@ -297,6 +343,11 @@ export class NameserverForm {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the edit row, restores its original values, removes validation errors,
|
||||
* and collapses the edit row while making the readonly row visible again.
|
||||
* @param {HTMLElement} editRow - The row that is being reset and collapsed.
|
||||
*/
|
||||
resetEditRowAndFormAndCollapseEditRow(editRow) {
|
||||
let readOnlyRow = editRow.previousElementSibling; // Get the next row
|
||||
if (!editRow || !readOnlyRow) {
|
||||
|
@ -318,6 +369,10 @@ export class NameserverForm {
|
|||
showElement(readOnlyRow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the 'Add Nameserver' form by clearing its input fields, removing errors,
|
||||
* and hiding the form to return it to its initial state.
|
||||
*/
|
||||
resetAddNameserversForm() {
|
||||
if (this.addNameserversForm) {
|
||||
// reset the values set in addNameserversForm
|
||||
|
@ -333,107 +388,150 @@ export class NameserverForm {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets all text input fields within the specified DOM element to their initial values.
|
||||
* Triggers an 'input' event to ensure any event listeners update accordingly.
|
||||
* @param {HTMLElement} domElement - The parent element containing text input fields to be reset.
|
||||
*/
|
||||
resetInputValuesInElement(domElement) {
|
||||
const inputEvent = new Event('input');
|
||||
let textInputs = domElement.querySelectorAll("input[type='text']");
|
||||
textInputs.forEach(input => {
|
||||
// Reset input value to its initial stored value
|
||||
input.value = input.dataset.initialValue;
|
||||
// Dispatch input event to update any event-driven changes
|
||||
input.dispatchEvent(inputEvent);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies values from the editable row's text inputs into the corresponding
|
||||
* readonly row cells, formatting them appropriately.
|
||||
* @param {HTMLElement} editRow - The row containing editable input fields.
|
||||
* @param {HTMLElement} readOnlyRow - The row where values will be displayed in a non-editable format.
|
||||
*/
|
||||
copyEditRowToReadonlyRow(editRow, readOnlyRow) {
|
||||
let textInputs = editRow.querySelectorAll("input[type='text']");
|
||||
let tds = readOnlyRow.querySelectorAll("td");
|
||||
let updatedText = '';
|
||||
|
||||
// if server is defined, copy the value to the first td in readOnlyRow
|
||||
// If a server name exists, store its value
|
||||
if (textInputs[0]) {
|
||||
updatedText = textInputs[0].value;
|
||||
//tds[0].innerText = textInputs[0].value;
|
||||
}
|
||||
|
||||
// if ip is defined, copy the value to the second td in readOnlyRow
|
||||
if (textInputs[1]) {
|
||||
if (textInputs[1].value) {
|
||||
updatedText = updatedText + "(" + textInputs[1].value + ")";
|
||||
}
|
||||
//tds[1].innerText = textInputs[1].value;
|
||||
// If an IP address exists, append it in parentheses next to the server name
|
||||
if (textInputs[1] && textInputs[1].value) {
|
||||
updatedText = updatedText + " (" + textInputs[1].value + ")";
|
||||
}
|
||||
|
||||
// Assign the formatted text to the first column of the readonly row
|
||||
if (tds[0]) {
|
||||
tds[0].innerText = updatedText;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all error-related classes and messages from the specified DOM element.
|
||||
* This method cleans up validation errors by removing error highlighting from input fields,
|
||||
* labels, and form groups, as well as deleting error message elements.
|
||||
* @param {HTMLElement} domElement - The parent element within which errors should be cleared.
|
||||
*/
|
||||
removeErrorsFromElement(domElement) {
|
||||
// remove class 'usa-form-group--error' from divs in domElement
|
||||
// Remove the 'usa-form-group--error' class from all div elements
|
||||
domElement.querySelectorAll("div.usa-form-group--error").forEach(div => {
|
||||
div.classList.remove("usa-form-group--error");
|
||||
});
|
||||
|
||||
// remove class 'usa-label--error' from labels in domElement
|
||||
// Remove the 'usa-label--error' class from all label elements
|
||||
domElement.querySelectorAll("label.usa-label--error").forEach(label => {
|
||||
label.classList.remove("usa-label--error");
|
||||
});
|
||||
|
||||
// Remove divs whose id ends with '__error-message' (error message divs)
|
||||
// Remove all error message divs whose ID ends with '__error-message'
|
||||
domElement.querySelectorAll("div[id$='__error-message']").forEach(errorDiv => {
|
||||
errorDiv.remove();
|
||||
});
|
||||
|
||||
// remove class 'usa-input--error' from inputs in domElement
|
||||
// Remove the 'usa-input--error' class from all input elements
|
||||
domElement.querySelectorAll("input.usa-input--error").forEach(input => {
|
||||
input.classList.remove("usa-input--error");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all form-level error messages displayed in the UI.
|
||||
* The form error messages are contained within div elements with the ID 'form-errors'.
|
||||
* Since multiple elements with the same ID may exist (even though not syntactically correct),
|
||||
* this function removes them iteratively.
|
||||
*/
|
||||
removeFormErrors() {
|
||||
// form errors have div id of form-errors. there can be multiple divs
|
||||
// with same id, which is not syntactically correct, but is the case,
|
||||
// so need to do below recursively
|
||||
let formErrorDiv = document.getElementById("form-errors");
|
||||
|
||||
// Recursively remove all instances of form error divs
|
||||
while (formErrorDiv) {
|
||||
formErrorDiv.remove();
|
||||
formErrorDiv = document.getElementById("form-errors");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resets the form change state.
|
||||
* This method marks the form as unchanged by setting `formChanged` to false.
|
||||
* It is useful for tracking whether a user has modified any form fields.
|
||||
*/
|
||||
resetFormChanged() {
|
||||
this.formChanged = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all existing alert messages from the main content area.
|
||||
* This ensures that only the latest alert is displayed to the user.
|
||||
*/
|
||||
resetAlerts() {
|
||||
const mainContent = document.querySelector("main#main-content");
|
||||
if (mainContent) {
|
||||
// Remove all alert elements within the main content area
|
||||
mainContent.querySelectorAll(".usa-alert").forEach(alert => alert.remove());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Displays an alert message at the top of the main content area.
|
||||
* It first removes any existing alerts before adding a new one to ensure only the latest alert is visible.
|
||||
* @param {string} level - The alert level (e.g., 'error', 'success', 'warning', 'info').
|
||||
* @param {string} message - The message to display inside the alert.
|
||||
*/
|
||||
addAlert(level, message) {
|
||||
this.resetAlerts();
|
||||
this.resetAlerts(); // Remove any existing alerts before adding a new one
|
||||
|
||||
const mainContent = document.querySelector("main#main-content");
|
||||
if (!mainContent) return;
|
||||
|
||||
|
||||
// Create a new alert div with appropriate classes based on alert level
|
||||
const alertDiv = document.createElement("div");
|
||||
alertDiv.className = `usa-alert usa-alert--${level} usa-alert--slim margin-bottom-2`;
|
||||
|
||||
|
||||
// Create the alert body to hold the message text
|
||||
const alertBody = document.createElement("div");
|
||||
alertBody.className = "usa-alert__body";
|
||||
alertBody.textContent = message;
|
||||
|
||||
|
||||
// Append the alert body to the alert div and insert it at the top of the main content area
|
||||
alertDiv.appendChild(alertBody);
|
||||
mainContent.insertBefore(alertDiv, mainContent.firstChild);
|
||||
scrollToElement("class","usa-alert__body");
|
||||
}
|
||||
|
||||
// Scroll the page to make the alert visible to the user
|
||||
scrollToElement("class", "usa-alert__body");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the NameserverForm when the DOM is fully loaded.
|
||||
*/
|
||||
export function initFormNameservers() {
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
|
||||
// Initialize NameserverForm if nameserver-add-button button is present in DOM
|
||||
if (document.getElementById('nameserver-add-button')) {
|
||||
const nameserverForm = new NameserverForm();
|
||||
nameserverForm.init();
|
||||
|
|
|
@ -47,8 +47,17 @@
|
|||
|
||||
<p>Add a name server record by clicking "Add name servers". You must add at least two name servers (13 max).</p>
|
||||
|
||||
{% comment %}
|
||||
This template supports the rendering of three different types of nameserver forms, conditionally displayed:
|
||||
1 - Add New Namervers form (rendered when there are no existing nameservers defined for the domain)
|
||||
2 - Nameserver table (rendered when the domain has existing nameservers, which can be viewed and edited)
|
||||
3 - Add New Nameserver (rendered above the Nameserver table to add a single additional nameserver)
|
||||
{% endcomment %}
|
||||
|
||||
{% if formset.initial and formset.forms.0.initial %}
|
||||
|
||||
{% comment %}This section renders both the Nameserver table and the Add New Nameserver {% endcomment %}
|
||||
|
||||
{% include "includes/required_fields.html" %}
|
||||
<form class="usa-form usa-form--extra-large" method="post" novalidate>
|
||||
{% csrf_token %}
|
||||
|
@ -56,6 +65,12 @@
|
|||
|
||||
{% for form in formset %}
|
||||
{% if forloop.last and not form.initial %}
|
||||
|
||||
{% comment %}
|
||||
This section renders the Add New Nameserver form.
|
||||
This section does not render if the last form has initial data (this occurs if 13 nameservers already exist)
|
||||
{% endcomment %}
|
||||
|
||||
<section class="add-nameservers-form display-none section-outlined">
|
||||
{{ form.domain }}
|
||||
<h2>Add a name server</h2>
|
||||
|
@ -106,6 +121,12 @@
|
|||
<tbody>
|
||||
{% for form in formset %}
|
||||
{% if not forloop.last or form.initial %}
|
||||
|
||||
{% comment %}
|
||||
This section renders table rows for each existing nameserver. Two rows are rendered, a readonly row
|
||||
and an edit row. Only one of which is displayed at a time.
|
||||
{% endcomment %}
|
||||
|
||||
{{ form.domain }}
|
||||
<!-- Readonly row -->
|
||||
<tr>
|
||||
|
@ -205,10 +226,9 @@
|
|||
{% else %}
|
||||
|
||||
{% comment %}
|
||||
No Nameservers.
|
||||
We use the double-decker form
|
||||
This section renders Add New Nameservers form which renders when there are no existing
|
||||
nameservers defined on the domain.
|
||||
{% endcomment %}
|
||||
|
||||
|
||||
<section class="add-nameservers-form display-none section-outlined">
|
||||
{% include "includes/required_fields.html" %}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue