Slight markup change and some JS to allow for deleting ns 1 and 2 when there are enough records in the formset

This commit is contained in:
Rachid Mrad 2023-10-26 13:20:45 -04:00
parent 4fdbb23141
commit d07f7b614b
No known key found for this signature in database
GPG key ID: EF38E4CEC4A8F3CF
4 changed files with 109 additions and 44 deletions

View file

@ -256,7 +256,7 @@ function prepareDeleteButtons(formLabel) {
let formNumberRegex = RegExp(`form-(\\d){1}-`, 'g'); let formNumberRegex = RegExp(`form-(\\d){1}-`, 'g');
let formLabelRegex = RegExp(`${formLabel} (\\d+){1}`, 'g'); let formLabelRegex = RegExp(`${formLabel} (\\d+){1}`, 'g');
// For the eample on Nameservers // For the example on Nameservers
let formExampleRegex = RegExp(`ns(\\d+){1}`, 'g'); let formExampleRegex = RegExp(`ns(\\d+){1}`, 'g');
forms.forEach((form, index) => { forms.forEach((form, index) => {
@ -275,31 +275,35 @@ function prepareDeleteButtons(formLabel) {
// h2 and legend for DS form, label for nameservers // h2 and legend for DS form, label for nameservers
Array.from(form.querySelectorAll('h2, legend, label, p')).forEach((node) => { Array.from(form.querySelectorAll('h2, legend, label, p')).forEach((node) => {
// Ticket: 1192 // If the node is a nameserver label, one of the first 2 which was previously 3 and up (not required)
// if (isNameserversForm && index <= 1 && !node.innerHTML.includes('*')) { // inject the USWDS required markup and make sure the INPUT is required
// // Create a new element if (isNameserversForm && index <= 1 && node.innerHTML.includes('server') && !node.innerHTML.includes('*')) {
// const newElement = document.createElement('abbr'); // Create a new element
// newElement.textContent = '*'; const newElement = document.createElement('abbr');
// // TODO: finish building abbr newElement.textContent = '*';
newElement.setAttribute("title", "required");
newElement.classList.add("usa-hint", "usa-hint--required");
// // Append the new element to the parent // Append the new element to the label
// node.appendChild(newElement); node.appendChild(newElement);
// // Find the next sibling that is an input element // Find the next sibling that is an input element
// let nextInputElement = node.nextElementSibling; let nextInputElement = node.nextElementSibling;
// while (nextInputElement) { while (nextInputElement) {
// if (nextInputElement.tagName === 'INPUT') { if (nextInputElement.tagName === 'INPUT') {
// // Found the next input element // Found the next input element
// console.log(nextInputElement); nextInputElement.setAttribute("required", "")
// break; break;
// } }
// nextInputElement = nextInputElement.nextElementSibling; nextInputElement = nextInputElement.nextElementSibling;
// } }
// nextInputElement.required = true; nextInputElement.required = true;
// } }
// Ticket: 1192 - remove if let innerSpan = node.querySelector('span')
if (!(isNameserversForm && index <= 1)) { if (innerSpan) {
innerSpan.textContent = innerSpan.textContent.replace(formLabelRegex, `${formLabel} ${index + 1}`);
} else {
node.textContent = node.textContent.replace(formLabelRegex, `${formLabel} ${index + 1}`); node.textContent = node.textContent.replace(formLabelRegex, `${formLabel} ${index + 1}`);
node.textContent = node.textContent.replace(formExampleRegex, `ns${index + 1}`); node.textContent = node.textContent.replace(formExampleRegex, `ns${index + 1}`);
} }
@ -310,6 +314,13 @@ function prepareDeleteButtons(formLabel) {
addButton.classList.remove("display-none") addButton.classList.remove("display-none")
} }
if (isNameserversForm && forms.length < 3) {
// Hide the delete buttons on the remaining nameservers
Array.from(form.querySelectorAll('.delete-record')).forEach((deleteButton) => {
deleteButton.classList.add("display-none");
});
}
}); });
} }
} }
@ -351,6 +362,33 @@ function prepareDeleteButtons(formLabel) {
// For the eample on Nameservers // For the eample on Nameservers
let formExampleRegex = RegExp(`ns(\\d){1}`, 'g'); let formExampleRegex = RegExp(`ns(\\d){1}`, 'g');
// Some Nameserver form checks since the delete can mess up the source object we're copying
// in regards to required fileds and hidden delete buttons
if (isNameserversForm) {
// If the source element we're copying has required on an input,
// reset that input
let formRequiredNeedsCleanUp = newForm.innerHTML.includes('*');
if (formRequiredNeedsCleanUp) {
newForm.querySelector('label abbr').remove();
// Get all input elements within the container
const inputElements = newForm.querySelectorAll("input");
// Loop through each input element and remove the 'required' attribute
inputElements.forEach((input) => {
if (input.hasAttribute("required")) {
input.removeAttribute("required");
}
});
}
// If the source element we're copying has an invisible delete button,
// show that button
let deleteButtonNeedsCleanUp = newForm.querySelector('.delete-record').classList.contains("display-none");
if (deleteButtonNeedsCleanUp) {
newForm.querySelector('.delete-record').classList.remove("display-none");
}
}
formNum++; formNum++;
newForm.innerHTML = newForm.innerHTML.replace(formNumberRegex, `form-${formNum-1}-`); newForm.innerHTML = newForm.innerHTML.replace(formNumberRegex, `form-${formNum-1}-`);
newForm.innerHTML = newForm.innerHTML.replace(formLabelRegex, `${formLabel} ${formNum}`); newForm.innerHTML = newForm.innerHTML.replace(formLabelRegex, `${formLabel} ${formNum}`);
@ -404,6 +442,15 @@ function prepareDeleteButtons(formLabel) {
if (isNameserversForm && formNum == 13) { if (isNameserversForm && formNum == 13) {
addButton.classList.add("display-none") addButton.classList.add("display-none")
} }
if (isNameserversForm && forms.length >= 2) {
// Show the delete buttons on the nameservers
forms.forEach((form, index) => {
Array.from(form.querySelectorAll('.delete-record')).forEach((deleteButton) => {
deleteButton.classList.remove("display-none");
});
});
}
} }
})(); })();

View file

@ -1,8 +1,11 @@
"""Forms for domain management.""" """Forms for domain management."""
from collections.abc import Mapping
from typing import Any
from django import forms from django import forms
from django.core.validators import MinValueValidator, MaxValueValidator, RegexValidator from django.core.validators import MinValueValidator, MaxValueValidator, RegexValidator
from django.forms import formset_factory from django.forms import formset_factory
from django.forms.utils import ErrorList
from phonenumber_field.widgets import RegionalPhoneNumberWidget from phonenumber_field.widgets import RegionalPhoneNumberWidget
from registrar.utility.errors import ( from registrar.utility.errors import (
@ -23,19 +26,30 @@ class DomainAddUserForm(forms.Form):
email = forms.EmailField(label="Email") email = forms.EmailField(label="Email")
class IPAddressField(forms.CharField):
def validate(self, value):
super().validate(value) # Run the default CharField validation
class DomainNameserverForm(forms.Form): class DomainNameserverForm(forms.Form):
"""Form for changing nameservers.""" """Form for changing nameservers."""
domain = forms.CharField(widget=forms.HiddenInput, required=False) domain = forms.CharField(widget=forms.HiddenInput, required=False)
server = forms.CharField(label="Name server", strip=True) server = forms.CharField(
label="Name server",
strip=True
ip = forms.CharField(label="IP Address (IPv4 or IPv6)", strip=True, required=False) )
ip = forms.CharField(
label="IP Address (IPv4 or IPv6)",
strip=True,
required=False,
)
def __init__(self, *args, **kwargs):
super(DomainNameserverForm, self).__init__(*args, **kwargs)
# add custom error messages
self.fields['server'].error_messages.update({
'required': 'A minimum of 2 Name Servers are required.',
})
def clean(self): def clean(self):
# clean is called from clean_forms, which is called from is_valid # clean is called from clean_forms, which is called from is_valid

View file

@ -2,7 +2,11 @@
class="{% if label_classes %} {{ label_classes }}{% endif %}{% if label_tag == 'legend' %} {{ legend_classes }}{% endif %}" class="{% if label_classes %} {{ label_classes }}{% endif %}{% if label_tag == 'legend' %} {{ legend_classes }}{% endif %}"
{% if not field.use_fieldset %}for="{{ widget.attrs.id }}"{% endif %} {% if not field.use_fieldset %}for="{{ widget.attrs.id }}"{% endif %}
> >
{% if span_for_text %}
<span>{{ field.label }}</span>
{% else %}
{{ field.label }} {{ field.label }}
{% endif %}
{% if widget.attrs.required %} {% if widget.attrs.required %}
<abbr class="usa-hint usa-hint--required" title="required">*</abbr> <abbr class="usa-hint usa-hint--required" title="required">*</abbr>
{% endif %} {% endif %}

View file

@ -35,11 +35,14 @@
{{ form.domain }} {{ form.domain }}
{% with sublabel_text="Example: ns"|concat:forloop.counter|concat:".example.com" %} {% with sublabel_text="Example: ns"|concat:forloop.counter|concat:".example.com" %}
{% if forloop.counter <= 2 %} {% if forloop.counter <= 2 %}
{% with attr_required=True add_group_class="usa-form-group--unstyled-error" %} {# span_for_text will wrap the copy in s <span>, which we'll use in the JS for this component #}
{% with attr_required=True add_group_class="usa-form-group--unstyled-error" span_for_text=True %}
{% input_with_errors form.server %} {% input_with_errors form.server %}
{% endwith %} {% endwith %}
{% else %} {% else %}
{% with span_for_text=True %}
{% input_with_errors form.server %} {% input_with_errors form.server %}
{% endwith %}
{% endif %} {% endif %}
{% endwith %} {% endwith %}
</div> </div>
@ -49,14 +52,11 @@
{% endwith %} {% endwith %}
</div> </div>
<div class="tablet:grid-col-2"> <div class="tablet:grid-col-2">
{% comment %} TODO: remove this if for 1192 {% endcomment %}
{% if forloop.counter > 2 %}
<button type="button" class="usa-button usa-button--unstyled display-block delete-record margin-bottom-075"> <button type="button" class="usa-button usa-button--unstyled display-block delete-record margin-bottom-075">
<svg class="usa-icon" aria-hidden="true" focusable="false" role="img" width="24" height="24"> <svg class="usa-icon" aria-hidden="true" focusable="false" role="img" width="24" height="24">
<use xlink:href="{%static 'img/sprite.svg'%}#delete"></use> <use xlink:href="{%static 'img/sprite.svg'%}#delete"></use>
</svg><span class="margin-left-05">Delete</span> </svg><span class="margin-left-05">Delete</span>
</button> </button>
{% endif %}
</div> </div>
</div> </div>
</div> </div>