From b4214300246ecd0306bff93983370a6ee61b8312 Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Wed, 17 Jul 2024 10:50:01 -0700 Subject: [PATCH 01/20] Test out copy functionality --- src/registrar/templates/admin/change_form.html | 5 +++++ .../templates/admin/change_form_object_tools.html | 9 ++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/registrar/templates/admin/change_form.html b/src/registrar/templates/admin/change_form.html index 78dac9ac0..3efbe554e 100644 --- a/src/registrar/templates/admin/change_form.html +++ b/src/registrar/templates/admin/change_form.html @@ -1,4 +1,5 @@ {% extends "admin/change_form.html" %} +{% load static i18n %} {% comment %} Replace the Django ul markup with a div. We'll edit the child markup accordingly in change_form_object_tools {% endcomment %} {% block object-tools %} @@ -10,3 +11,7 @@ {% endif %} {% endblock %} + +{% block extrahead %} + +{% endblock %} \ No newline at end of file diff --git a/src/registrar/templates/admin/change_form_object_tools.html b/src/registrar/templates/admin/change_form_object_tools.html index 28c655bbc..48a6b101d 100644 --- a/src/registrar/templates/admin/change_form_object_tools.html +++ b/src/registrar/templates/admin/change_form_object_tools.html @@ -16,5 +16,12 @@

{% translate "History" %}

+ {% if opts.model_name == 'domainrequest' %} +

+ + +

+ {% endif %} {% endif %} -{% endblock %} \ No newline at end of file +{% endblock %} + From 721e91aac75b77742c229dc7516d03fe865bd3b8 Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Wed, 17 Jul 2024 11:05:09 -0700 Subject: [PATCH 02/20] Add in js file --- src/registrar/assets/js/copy-summary.js | 34 +++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/registrar/assets/js/copy-summary.js diff --git a/src/registrar/assets/js/copy-summary.js b/src/registrar/assets/js/copy-summary.js new file mode 100644 index 000000000..42cedf008 --- /dev/null +++ b/src/registrar/assets/js/copy-summary.js @@ -0,0 +1,34 @@ + +document.addEventListener('DOMContentLoaded', function() { + document.getElementById('copy-summary-btn').addEventListener('click', function() { + // Generate the summary text + const organizationType = document.getElementById('id_organization_type').value; + const requestedDomain = document.getElementById('id_requested_domain').value; + const existingWebsites = Array.from(document.querySelectorAll('#id_current_websites')).map(el => el.text).join(', '); + const alternativeDomains = Array.from(document.querySelectorAll('#id_alternative_domains')).map(el => el.text).join(', '); + const submitter = document.getElementById('id_submitter').value; + const seniorOfficial = document.getElementById('id_senior_official').value; + const otherContacts = Array.from(document.querySelectorAll('#id_other_contacts option:checked')).map(el => el.text).join('\n* '); + + const summary = `*Recommendation:*\n\n` + + `*Organization Type:* ${organizationType}\n\n` + + `*Requested Domain:* ${requestedDomain}\n\n` + + `*Existing website(s):*\n${existingWebsites}\n\n` + + `*Rationale:*\n\n` + + `*Alternate Domain(s):*\n* ${alternativeDomains.split(', ').join('\n* ')}\n\n` + + `*Submitter:*\n\n* ${submitter}\n\n` + + `*Senior Official:*\n\n* ${seniorOfficial}\n\n` + + `*Additional Contact(s):*\n\n* ${otherContacts}\n\n`; + + // Create a temporary textarea element to hold the summary + const textArea = document.createElement('textarea'); + textArea.value = summary; + document.body.appendChild(textArea); + textArea.select(); + document.execCommand('copy'); + document.body.removeChild(textArea); + + alert('Summary copied to clipboard!'); + alert("hello"); + }); +}); From e19bcaf55f61cc52d7f43cd38df19378d47290e8 Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Wed, 17 Jul 2024 11:05:42 -0700 Subject: [PATCH 03/20] Remove extra line --- src/registrar/assets/js/copy-summary.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/registrar/assets/js/copy-summary.js b/src/registrar/assets/js/copy-summary.js index 42cedf008..9edad3f6b 100644 --- a/src/registrar/assets/js/copy-summary.js +++ b/src/registrar/assets/js/copy-summary.js @@ -29,6 +29,5 @@ document.addEventListener('DOMContentLoaded', function() { document.body.removeChild(textArea); alert('Summary copied to clipboard!'); - alert("hello"); }); }); From bc334bd41fe276eb386753d931a7e284fc44567c Mon Sep 17 00:00:00 2001 From: CocoByte Date: Mon, 22 Jul 2024 16:25:14 -0600 Subject: [PATCH 04/20] updated button format and javascript --- src/registrar/assets/js/copy-summary.js | 51 ++++++++++++------- .../admin/change_form_object_tools.html | 19 +++---- 2 files changed, 44 insertions(+), 26 deletions(-) diff --git a/src/registrar/assets/js/copy-summary.js b/src/registrar/assets/js/copy-summary.js index 9edad3f6b..b268956a5 100644 --- a/src/registrar/assets/js/copy-summary.js +++ b/src/registrar/assets/js/copy-summary.js @@ -8,25 +8,42 @@ document.addEventListener('DOMContentLoaded', function() { const alternativeDomains = Array.from(document.querySelectorAll('#id_alternative_domains')).map(el => el.text).join(', '); const submitter = document.getElementById('id_submitter').value; const seniorOfficial = document.getElementById('id_senior_official').value; - const otherContacts = Array.from(document.querySelectorAll('#id_other_contacts option:checked')).map(el => el.text).join('\n* '); + const otherContacts = Array.from(document.querySelectorAll('#id_other_contacts option:checked')).map(el => el.text).join('\n '); - const summary = `*Recommendation:*\n\n` + - `*Organization Type:* ${organizationType}\n\n` + - `*Requested Domain:* ${requestedDomain}\n\n` + - `*Existing website(s):*\n${existingWebsites}\n\n` + - `*Rationale:*\n\n` + - `*Alternate Domain(s):*\n* ${alternativeDomains.split(', ').join('\n* ')}\n\n` + - `*Submitter:*\n\n* ${submitter}\n\n` + - `*Senior Official:*\n\n* ${seniorOfficial}\n\n` + - `*Additional Contact(s):*\n\n* ${otherContacts}\n\n`; + const summary = `Recommendation:
` + + `Organization Type: ${organizationType}
` + + `Requested Domain: ${requestedDomain}
` + + `Existing website(s): ${existingWebsites}
` + + `Rationale:` + + `Alternate Domain(s): ${alternativeDomains.split(', ').join('\n ')}
` + + `Submitter: ${submitter}
` + + `Senior Official: ${seniorOfficial}
` + + `Additional Contact(s): ${otherContacts}
`; - // Create a temporary textarea element to hold the summary - const textArea = document.createElement('textarea'); - textArea.value = summary; - document.body.appendChild(textArea); - textArea.select(); - document.execCommand('copy'); - document.body.removeChild(textArea); + // Create a temporary element + let tempElement = document.createElement('div'); + tempElement.innerHTML = summary; + // Append the element to the body + document.body.appendChild(tempElement); + + // Use the Selection and Range APIs to select the element's content + let range = document.createRange(); + range.selectNodeContents(tempElement); + let selection = window.getSelection(); + selection.removeAllRanges(); + selection.addRange(range); + + // Use the Clipboard API to write the selected HTML content to the clipboard + navigator.clipboard.write([ + new ClipboardItem({ + 'text/html': new Blob([tempElement.innerHTML], { type: 'text/html' }) + }) + ]).then(() => { + console.log('Bold text copied to clipboard successfully!'); + }).catch(err => { + console.error('Failed to copy text: ', err); + }); + document.body.removeChild(tempElement); alert('Summary copied to clipboard!'); }); diff --git a/src/registrar/templates/admin/change_form_object_tools.html b/src/registrar/templates/admin/change_form_object_tools.html index 48a6b101d..c2d22e9e2 100644 --- a/src/registrar/templates/admin/change_form_object_tools.html +++ b/src/registrar/templates/admin/change_form_object_tools.html @@ -13,15 +13,16 @@ {% else %} -

- {% translate "History" %} -

- {% if opts.model_name == 'domainrequest' %} -

- - -

- {% endif %} + {% endif %} {% endblock %} From b245dfb2fe801506b3bbc3a0713d5551be8d8330 Mon Sep 17 00:00:00 2001 From: CocoByte Date: Tue, 23 Jul 2024 10:55:02 -0600 Subject: [PATCH 05/20] fixed dom extraction --- src/registrar/assets/js/copy-summary.js | 39 ++++++++++++++++++------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/src/registrar/assets/js/copy-summary.js b/src/registrar/assets/js/copy-summary.js index b268956a5..d12efb872 100644 --- a/src/registrar/assets/js/copy-summary.js +++ b/src/registrar/assets/js/copy-summary.js @@ -2,23 +2,40 @@ document.addEventListener('DOMContentLoaded', function() { document.getElementById('copy-summary-btn').addEventListener('click', function() { // Generate the summary text - const organizationType = document.getElementById('id_organization_type').value; - const requestedDomain = document.getElementById('id_requested_domain').value; - const existingWebsites = Array.from(document.querySelectorAll('#id_current_websites')).map(el => el.text).join(', '); - const alternativeDomains = Array.from(document.querySelectorAll('#id_alternative_domains')).map(el => el.text).join(', '); - const submitter = document.getElementById('id_submitter').value; - const seniorOfficial = document.getElementById('id_senior_official').value; - const otherContacts = Array.from(document.querySelectorAll('#id_other_contacts option:checked')).map(el => el.text).join('\n '); + + const organizationTypeElement = document.getElementById('id_organization_type'); + const organizationType = organizationTypeElement.options[organizationTypeElement.selectedIndex].text; + + const alternativeDomainsDiv = document.querySelector('.form-row.field-alternative_domains .readonly'); + const alternativeDomainslinks = alternativeDomainsDiv.querySelectorAll('a'); + const alternativeDomains = Array.from(alternativeDomainslinks).map(link => link.textContent); + + const existingWebsitesDiv = document.querySelector('.form-row.field-current_websites .readonly'); + const existingWebsiteslinks = existingWebsitesDiv.querySelectorAll('a'); + const existingWebsites = Array.from(existingWebsiteslinks).map(link => link.textContent); + + const otherContactsDiv = document.querySelector('.form-row.field-other_contacts .readonly'); + const otherContactslinks = otherContactsDiv.querySelectorAll('a'); + const otherContacts = Array.from(otherContactslinks).map(link => link.textContent); + + const requestedDomainElement = document.getElementById('id_requested_domain'); + const requestedDomain = requestedDomainElement.options[requestedDomainElement.selectedIndex].text; + + const submitterElement = document.getElementById('id_submitter'); + const submitter = submitterElement.options[submitterElement.selectedIndex].text; + + const seniorOfficialElement = document.getElementById('id_senior_official'); + const seniorOfficial = seniorOfficialElement.options[seniorOfficialElement.selectedIndex].text; const summary = `Recommendation:
` + `Organization Type: ${organizationType}
` + `Requested Domain: ${requestedDomain}
` + - `Existing website(s): ${existingWebsites}
` + - `Rationale:` + - `Alternate Domain(s): ${alternativeDomains.split(', ').join('\n ')}
` + + `Existing website(s): ${existingWebsites.join('
')}
` + + `Rationale:
` + + `Alternate Domain(s): ${alternativeDomains.join('
')}
` + `Submitter: ${submitter}
` + `Senior Official: ${seniorOfficial}
` + - `Additional Contact(s): ${otherContacts}
`; + `Additional Contact(s): ${otherContacts.join('
')}
`; // Create a temporary element let tempElement = document.createElement('div'); From c33a4b61f579f6e93f238521e0d39a66965e0996 Mon Sep 17 00:00:00 2001 From: CocoByte Date: Tue, 23 Jul 2024 13:42:02 -0600 Subject: [PATCH 06/20] fixed formatting --- src/registrar/assets/js/copy-summary.js | 63 ++++++++++++++++--- .../admin/includes/contact_detail_list.html | 19 +++--- 2 files changed, 65 insertions(+), 17 deletions(-) diff --git a/src/registrar/assets/js/copy-summary.js b/src/registrar/assets/js/copy-summary.js index d12efb872..c10adbffa 100644 --- a/src/registrar/assets/js/copy-summary.js +++ b/src/registrar/assets/js/copy-summary.js @@ -1,41 +1,86 @@ document.addEventListener('DOMContentLoaded', function() { document.getElementById('copy-summary-btn').addEventListener('click', function() { - // Generate the summary text + /// Generate the summary text + //------ Organization Type const organizationTypeElement = document.getElementById('id_organization_type'); const organizationType = organizationTypeElement.options[organizationTypeElement.selectedIndex].text; + //------ Alternative Domains const alternativeDomainsDiv = document.querySelector('.form-row.field-alternative_domains .readonly'); const alternativeDomainslinks = alternativeDomainsDiv.querySelectorAll('a'); const alternativeDomains = Array.from(alternativeDomainslinks).map(link => link.textContent); + //------ Existing Websites const existingWebsitesDiv = document.querySelector('.form-row.field-current_websites .readonly'); const existingWebsiteslinks = existingWebsitesDiv.querySelectorAll('a'); const existingWebsites = Array.from(existingWebsiteslinks).map(link => link.textContent); + //------ Additional Contacts + // 1 - Create a hyperlinks map so we can display contact details and also link to the contact const otherContactsDiv = document.querySelector('.form-row.field-other_contacts .readonly'); - const otherContactslinks = otherContactsDiv.querySelectorAll('a'); - const otherContacts = Array.from(otherContactslinks).map(link => link.textContent); + const otherContactLinks = otherContactsDiv.querySelectorAll('a'); + const nameToUrlMap = {}; + otherContactLinks.forEach(link => { + const name = link.textContent.trim(); + const url = link.href; + nameToUrlMap[name] = url; + }); + + // 2 - Iterate through contact details and assemble html for summary + let otherContactsSummary = "" + // Get the table rows of contact details + const otherContactsTable = document.querySelector('.form-row.field-other_contacts table tbody'); + const otherContactsRows = otherContactsTable.querySelectorAll('tr'); + const bulletList = document.createElement('ul'); + otherContactsRows.forEach(contactRow => { + // Extract the contact details + const name = contactRow.querySelector('th').textContent.trim(); + const title = contactRow.querySelectorAll('td')[0].textContent.trim(); + const email = contactRow.querySelectorAll('td')[1].textContent.trim(); + const phone = contactRow.querySelectorAll('td')[2].textContent.trim(); + const url = nameToUrlMap[name] || '#'; + // Format the contact information + const listItem = document.createElement('li'); + listItem.innerH = `${name}, ${title}, ${email}, ${phone}`; + bulletList.appendChild(listItem); + }); + otherContactsSummary += bulletList.outerHTML + + //------ Requested Domains const requestedDomainElement = document.getElementById('id_requested_domain'); const requestedDomain = requestedDomainElement.options[requestedDomainElement.selectedIndex].text; - const submitterElement = document.getElementById('id_submitter'); - const submitter = submitterElement.options[submitterElement.selectedIndex].text; + //------ Submitter + // Function to extract text by ID and handle missing elements + function extractTextById(id) { + const element = document.getElementById(id); + return element ? element.textContent.trim()+"," : ''; + } + // Extract the submitter name, title, email, and phone number + const submitterName = extractTextById('contact_info_name'); + const submitterTitle = extractTextById('contact_info_title'); + const submitterEmail = extractTextById('contact_info_email'); + const submitterPhone = extractTextById('contact_info_phone'); + // Format the contact information + let submitterInfo = `${submitterName} ${submitterTitle} ${submitterEmail} ${submitterPhone}`; + + //------ Senior Official const seniorOfficialElement = document.getElementById('id_senior_official'); const seniorOfficial = seniorOfficialElement.options[seniorOfficialElement.selectedIndex].text; const summary = `Recommendation:
` + `Organization Type: ${organizationType}
` + `Requested Domain: ${requestedDomain}
` + - `Existing website(s): ${existingWebsites.join('
')}
` + + `Existing website(s): ${existingWebsites.join(',')}
` + `Rationale:
` + - `Alternate Domain(s): ${alternativeDomains.join('
')}
` + - `Submitter: ${submitter}
` + + `Alternate Domain(s): ${alternativeDomains.join(',')}
` + + `Submitter: ${submitterInfo}
` + `Senior Official: ${seniorOfficial}
` + - `Additional Contact(s): ${otherContacts.join('
')}
`; + `Additional Contact(s): ${otherContactsSummary}
`; // Create a temporary element let tempElement = document.createElement('div'); diff --git a/src/registrar/templates/django/admin/includes/contact_detail_list.html b/src/registrar/templates/django/admin/includes/contact_detail_list.html index 2ee490d76..8358e5440 100644 --- a/src/registrar/templates/django/admin/includes/contact_detail_list.html +++ b/src/registrar/templates/django/admin/includes/contact_detail_list.html @@ -2,25 +2,28 @@
+ {% if show_formatted_name %} {% if user.get_formatted_name %} - {{ user.get_formatted_name }}
+ {{ user.get_formatted_name }} {% else %} - None
+ None {% endif %} {% endif %} +
{% if user.has_contact_info %} {# Title #} {% if user.title %} - {{ user.title }} -
+ {{ user.title }} {% else %} - None
+ None {% endif %} +
+ {# Email #} {% if user.email %} - {{ user.email }} + {{ user.email }} {% include "admin/input_with_clipboard.html" with field=user invisible_input_field=True %}
{% else %} @@ -29,7 +32,7 @@ {# Phone #} {% if user.phone %} - {{ user.phone }} + {{ user.phone.as_national }}
{% else %} None
@@ -40,6 +43,6 @@ {% endif %} {% if user_verification_type %} - {{ user_verification_type }} + {{ user_verification_type }} {% endif %}
From 4666da4df709502ff283c8b0592426a4088a4eae Mon Sep 17 00:00:00 2001 From: CocoByte Date: Tue, 23 Jul 2024 13:50:40 -0600 Subject: [PATCH 07/20] fix wierd typo --- src/registrar/assets/js/copy-summary.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/assets/js/copy-summary.js b/src/registrar/assets/js/copy-summary.js index c10adbffa..cd437f0a6 100644 --- a/src/registrar/assets/js/copy-summary.js +++ b/src/registrar/assets/js/copy-summary.js @@ -43,7 +43,7 @@ document.addEventListener('DOMContentLoaded', function() { const url = nameToUrlMap[name] || '#'; // Format the contact information const listItem = document.createElement('li'); - listItem.innerH = `${name}, ${title}, ${email}, ${phone}`; + listItem.innerHTML = `${name}, ${title}, ${email}, ${phone}`; bulletList.appendChild(listItem); }); otherContactsSummary += bulletList.outerHTML From 72fdcfdac05e834adac59e59f83ad2d1804134ef Mon Sep 17 00:00:00 2001 From: CocoByte Date: Tue, 23 Jul 2024 14:22:10 -0600 Subject: [PATCH 08/20] more formatting fixes --- src/registrar/assets/js/copy-summary.js | 33 ++++++++++++++++--------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/registrar/assets/js/copy-summary.js b/src/registrar/assets/js/copy-summary.js index cd437f0a6..824002f76 100644 --- a/src/registrar/assets/js/copy-summary.js +++ b/src/registrar/assets/js/copy-summary.js @@ -55,31 +55,40 @@ document.addEventListener('DOMContentLoaded', function() { //------ Submitter // Function to extract text by ID and handle missing elements - function extractTextById(id) { - const element = document.getElementById(id); - return element ? element.textContent.trim()+"," : ''; + function extractTextById(id, divElement) { + if (divElement) { + const element = divElement.querySelector(`#${id}`); + return element ? ", " + element.textContent.trim() : ''; + } + return ''; } // Extract the submitter name, title, email, and phone number - const submitterName = extractTextById('contact_info_name'); - const submitterTitle = extractTextById('contact_info_title'); - const submitterEmail = extractTextById('contact_info_email'); - const submitterPhone = extractTextById('contact_info_phone'); - // Format the contact information + const submitterDiv = document.querySelector('.form-row.field-submitter'); + const submitterNameElement = document.getElementById('id_submitter'); + const submitterName = submitterNameElement.options[submitterNameElement.selectedIndex].text; + const submitterTitle = extractTextById('contact_info_title', submitterDiv); + const submitterEmail = extractTextById('contact_info_email', submitterDiv); + const submitterPhone = extractTextById('contact_info_phone', submitterDiv); let submitterInfo = `${submitterName} ${submitterTitle} ${submitterEmail} ${submitterPhone}`; //------ Senior Official + const seniorOfficialDiv = document.querySelector('.form-row.field-senior_official'); const seniorOfficialElement = document.getElementById('id_senior_official'); - const seniorOfficial = seniorOfficialElement.options[seniorOfficialElement.selectedIndex].text; + const seniorOfficialName = seniorOfficialElement.options[seniorOfficialElement.selectedIndex].text; + const seniorOfficialTitle = extractTextById('contact_info_title', seniorOfficialDiv); + const seniorOfficialEmail = extractTextById('contact_info_email', seniorOfficialDiv); + const seniorOfficialPhone = extractTextById('contact_info_phone', seniorOfficialDiv); + let seniorOfficialInfo = `${seniorOfficialName} ${seniorOfficialTitle} ${seniorOfficialEmail} ${seniorOfficialPhone}`; const summary = `Recommendation:
` + `Organization Type: ${organizationType}
` + `Requested Domain: ${requestedDomain}
` + - `Existing website(s): ${existingWebsites.join(',')}
` + + `Existing website(s): ${existingWebsites.join(', ')}
` + `Rationale:
` + - `Alternate Domain(s): ${alternativeDomains.join(',')}
` + + `Alternate Domain(s): ${alternativeDomains.join(', ')}
` + `Submitter: ${submitterInfo}
` + - `Senior Official: ${seniorOfficial}
` + + `Senior Official: ${seniorOfficialInfo}
` + `Additional Contact(s): ${otherContactsSummary}
`; // Create a temporary element From 711c71c1147cfbc5a01d6e3c1c8240bfabd9ae98 Mon Sep 17 00:00:00 2001 From: CocoByte Date: Tue, 23 Jul 2024 14:37:58 -0600 Subject: [PATCH 09/20] Catching edge-cases --- src/registrar/assets/js/copy-summary.js | 55 ++++++++++--------- .../admin/includes/contact_detail_list.html | 2 +- 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/src/registrar/assets/js/copy-summary.js b/src/registrar/assets/js/copy-summary.js index 824002f76..de15596d2 100644 --- a/src/registrar/assets/js/copy-summary.js +++ b/src/registrar/assets/js/copy-summary.js @@ -1,7 +1,7 @@ document.addEventListener('DOMContentLoaded', function() { document.getElementById('copy-summary-btn').addEventListener('click', function() { - /// Generate the summary text + /// Generate a rich HTML summary text and copy to clipboard //------ Organization Type const organizationTypeElement = document.getElementById('id_organization_type'); @@ -20,33 +20,38 @@ document.addEventListener('DOMContentLoaded', function() { //------ Additional Contacts // 1 - Create a hyperlinks map so we can display contact details and also link to the contact const otherContactsDiv = document.querySelector('.form-row.field-other_contacts .readonly'); - const otherContactLinks = otherContactsDiv.querySelectorAll('a'); - const nameToUrlMap = {}; - otherContactLinks.forEach(link => { - const name = link.textContent.trim(); - const url = link.href; - nameToUrlMap[name] = url; - }); + let otherContactLinks = []; + if (otherContactsDiv) { + otherContactLinks = otherContactsDiv.querySelectorAll('a'); + const nameToUrlMap = {}; + otherContactLinks.forEach(link => { + const name = link.textContent.trim(); + const url = link.href; + nameToUrlMap[name] = url; + }); + } // 2 - Iterate through contact details and assemble html for summary let otherContactsSummary = "" // Get the table rows of contact details const otherContactsTable = document.querySelector('.form-row.field-other_contacts table tbody'); - const otherContactsRows = otherContactsTable.querySelectorAll('tr'); - const bulletList = document.createElement('ul'); - otherContactsRows.forEach(contactRow => { - // Extract the contact details - const name = contactRow.querySelector('th').textContent.trim(); - const title = contactRow.querySelectorAll('td')[0].textContent.trim(); - const email = contactRow.querySelectorAll('td')[1].textContent.trim(); - const phone = contactRow.querySelectorAll('td')[2].textContent.trim(); - const url = nameToUrlMap[name] || '#'; - // Format the contact information - const listItem = document.createElement('li'); - listItem.innerHTML = `${name}, ${title}, ${email}, ${phone}`; - bulletList.appendChild(listItem); - }); - otherContactsSummary += bulletList.outerHTML + if (otherContactsTable) { + const otherContactsRows = otherContactsTable.querySelectorAll('tr'); + const bulletList = document.createElement('ul'); + otherContactsRows.forEach(contactRow => { + // Extract the contact details + const name = contactRow.querySelector('th').textContent.trim(); + const title = contactRow.querySelectorAll('td')[0].textContent.trim(); + const email = contactRow.querySelectorAll('td')[1].textContent.trim(); + const phone = contactRow.querySelectorAll('td')[2].textContent.trim(); + const url = nameToUrlMap[name] || '#'; + // Format the contact information + const listItem = document.createElement('li'); + listItem.innerHTML = `${name}, ${title}, ${email}, ${phone}`; + bulletList.appendChild(listItem); + }); + otherContactsSummary += bulletList.outerHTML + } //------ Requested Domains @@ -69,7 +74,7 @@ document.addEventListener('DOMContentLoaded', function() { const submitterTitle = extractTextById('contact_info_title', submitterDiv); const submitterEmail = extractTextById('contact_info_email', submitterDiv); const submitterPhone = extractTextById('contact_info_phone', submitterDiv); - let submitterInfo = `${submitterName} ${submitterTitle} ${submitterEmail} ${submitterPhone}`; + let submitterInfo = `${submitterName}${submitterTitle}${submitterEmail}${submitterPhone}`; //------ Senior Official @@ -79,7 +84,7 @@ document.addEventListener('DOMContentLoaded', function() { const seniorOfficialTitle = extractTextById('contact_info_title', seniorOfficialDiv); const seniorOfficialEmail = extractTextById('contact_info_email', seniorOfficialDiv); const seniorOfficialPhone = extractTextById('contact_info_phone', seniorOfficialDiv); - let seniorOfficialInfo = `${seniorOfficialName} ${seniorOfficialTitle} ${seniorOfficialEmail} ${seniorOfficialPhone}`; + let seniorOfficialInfo = `${seniorOfficialName}${seniorOfficialTitle}${seniorOfficialEmail}${seniorOfficialPhone}`; const summary = `Recommendation:
` + `Organization Type: ${organizationType}
` + diff --git a/src/registrar/templates/django/admin/includes/contact_detail_list.html b/src/registrar/templates/django/admin/includes/contact_detail_list.html index 8358e5440..418d1464b 100644 --- a/src/registrar/templates/django/admin/includes/contact_detail_list.html +++ b/src/registrar/templates/django/admin/includes/contact_detail_list.html @@ -32,7 +32,7 @@ {# Phone #} {% if user.phone %} - {{ user.phone.as_national }} + {{ user.phone }}
{% else %} None
From 53e1fe96931b584b824bf474c7c30126681d4614 Mon Sep 17 00:00:00 2001 From: CocoByte Date: Tue, 30 Jul 2024 13:31:38 -0600 Subject: [PATCH 10/20] update code for extracting "other contact" details --- src/registrar/assets/js/copy-summary.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/registrar/assets/js/copy-summary.js b/src/registrar/assets/js/copy-summary.js index de15596d2..2416b07bb 100644 --- a/src/registrar/assets/js/copy-summary.js +++ b/src/registrar/assets/js/copy-summary.js @@ -34,16 +34,16 @@ document.addEventListener('DOMContentLoaded', function() { // 2 - Iterate through contact details and assemble html for summary let otherContactsSummary = "" // Get the table rows of contact details - const otherContactsTable = document.querySelector('.form-row.field-other_contacts table tbody'); - if (otherContactsTable) { - const otherContactsRows = otherContactsTable.querySelectorAll('tr'); - const bulletList = document.createElement('ul'); - otherContactsRows.forEach(contactRow => { - // Extract the contact details - const name = contactRow.querySelector('th').textContent.trim(); - const title = contactRow.querySelectorAll('td')[0].textContent.trim(); - const email = contactRow.querySelectorAll('td')[1].textContent.trim(); - const phone = contactRow.querySelectorAll('td')[2].textContent.trim(); + // Select all contact elements + const contacts = document.querySelectorAll('.dja-detail-list dl'); + + // Iterate through each contact element + contacts.forEach(contact => { + const name = contact.querySelector('a#contact_info_name').innerText; + const title = contact.querySelector('span#contact_info_title').innerText; + const email = contact.querySelector('span#contact_info_email').innerText; + const phone = contact.querySelector('span#contact_info_phone').innerText; + const url = nameToUrlMap[name] || '#'; // Format the contact information const listItem = document.createElement('li'); @@ -51,7 +51,7 @@ document.addEventListener('DOMContentLoaded', function() { bulletList.appendChild(listItem); }); otherContactsSummary += bulletList.outerHTML - } + }); //------ Requested Domains From e446aa9511fa98b3655cbe79ec601c75a89d10e1 Mon Sep 17 00:00:00 2001 From: CocoByte Date: Tue, 30 Jul 2024 16:05:15 -0600 Subject: [PATCH 11/20] copy logic updates, icon updates --- src/registrar/assets/js/copy-summary.js | 12 +++++------- .../templates/admin/change_form_object_tools.html | 8 +++++++- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/registrar/assets/js/copy-summary.js b/src/registrar/assets/js/copy-summary.js index 2416b07bb..178f61185 100644 --- a/src/registrar/assets/js/copy-summary.js +++ b/src/registrar/assets/js/copy-summary.js @@ -21,9 +21,9 @@ document.addEventListener('DOMContentLoaded', function() { // 1 - Create a hyperlinks map so we can display contact details and also link to the contact const otherContactsDiv = document.querySelector('.form-row.field-other_contacts .readonly'); let otherContactLinks = []; + const nameToUrlMap = {}; if (otherContactsDiv) { otherContactLinks = otherContactsDiv.querySelectorAll('a'); - const nameToUrlMap = {}; otherContactLinks.forEach(link => { const name = link.textContent.trim(); const url = link.href; @@ -38,20 +38,20 @@ document.addEventListener('DOMContentLoaded', function() { const contacts = document.querySelectorAll('.dja-detail-list dl'); // Iterate through each contact element + const bulletList = document.createElement('ul'); contacts.forEach(contact => { const name = contact.querySelector('a#contact_info_name').innerText; const title = contact.querySelector('span#contact_info_title').innerText; const email = contact.querySelector('span#contact_info_email').innerText; const phone = contact.querySelector('span#contact_info_phone').innerText; - const url = nameToUrlMap[name] || '#'; + // Format the contact information const listItem = document.createElement('li'); listItem.innerHTML = `${name}, ${title}, ${email}, ${phone}`; bulletList.appendChild(listItem); - }); - otherContactsSummary += bulletList.outerHTML }); + otherContactsSummary += bulletList.outerHTML //------ Requested Domains @@ -115,12 +115,10 @@ document.addEventListener('DOMContentLoaded', function() { 'text/html': new Blob([tempElement.innerHTML], { type: 'text/html' }) }) ]).then(() => { - console.log('Bold text copied to clipboard successfully!'); + console.log('Summary copied to clipboard successfully!'); }).catch(err => { console.error('Failed to copy text: ', err); }); document.body.removeChild(tempElement); - - alert('Summary copied to clipboard!'); }); }); diff --git a/src/registrar/templates/admin/change_form_object_tools.html b/src/registrar/templates/admin/change_form_object_tools.html index c2d22e9e2..1094f4c86 100644 --- a/src/registrar/templates/admin/change_form_object_tools.html +++ b/src/registrar/templates/admin/change_form_object_tools.html @@ -1,4 +1,5 @@ {% load i18n admin_urls %} +{% load i18n static %} {% comment %} Replace li with p for more semantic HTML if we have a single child {% endcomment %} {% block object-tools-items %} @@ -19,7 +20,12 @@ {% if opts.model_name == 'domainrequest' %}
  • - {% translate "Copy request summary" %} + + + + + {% translate "Copy request summary" %} +
  • {% endif %} From 0953e50bb0d01155436f1ec5ab49e971d19cbbe6 Mon Sep 17 00:00:00 2001 From: CocoByte Date: Tue, 30 Jul 2024 17:39:02 -0600 Subject: [PATCH 12/20] styling updates --- src/registrar/assets/sass/_theme/_buttons.scss | 5 +++++ src/registrar/templates/admin/change_form_object_tools.html | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/registrar/assets/sass/_theme/_buttons.scss b/src/registrar/assets/sass/_theme/_buttons.scss index 7fa379c0b..577c9ce29 100644 --- a/src/registrar/assets/sass/_theme/_buttons.scss +++ b/src/registrar/assets/sass/_theme/_buttons.scss @@ -128,6 +128,11 @@ a.withdraw:active { vertical-align: bottom; } +a.historylink .usa-icon { + vertical-align: middle; + margin: 0px; +} + a.usa-button--unstyled:visited { color: color('primary'); } diff --git a/src/registrar/templates/admin/change_form_object_tools.html b/src/registrar/templates/admin/change_form_object_tools.html index 1094f4c86..03c519241 100644 --- a/src/registrar/templates/admin/change_form_object_tools.html +++ b/src/registrar/templates/admin/change_form_object_tools.html @@ -22,7 +22,7 @@
  • - + {% translate "Copy request summary" %} From 7b56562417f3a5c2eb5b8e8982eabf9c3092860e Mon Sep 17 00:00:00 2001 From: CocoByte Date: Tue, 30 Jul 2024 18:45:44 -0600 Subject: [PATCH 13/20] Fixed error with javascript file, more styling --- src/registrar/assets/js/copy-summary.js | 124 ------------- src/registrar/assets/js/get-gov-admin.js | 163 +++++++++++++++++- .../assets/sass/_theme/_buttons.scss | 7 +- src/registrar/assets/sass/_theme/_links.scss | 5 + .../templates/admin/change_form.html | 4 - .../admin/change_form_object_tools.html | 6 +- 6 files changed, 165 insertions(+), 144 deletions(-) delete mode 100644 src/registrar/assets/js/copy-summary.js diff --git a/src/registrar/assets/js/copy-summary.js b/src/registrar/assets/js/copy-summary.js deleted file mode 100644 index 178f61185..000000000 --- a/src/registrar/assets/js/copy-summary.js +++ /dev/null @@ -1,124 +0,0 @@ - -document.addEventListener('DOMContentLoaded', function() { - document.getElementById('copy-summary-btn').addEventListener('click', function() { - /// Generate a rich HTML summary text and copy to clipboard - - //------ Organization Type - const organizationTypeElement = document.getElementById('id_organization_type'); - const organizationType = organizationTypeElement.options[organizationTypeElement.selectedIndex].text; - - //------ Alternative Domains - const alternativeDomainsDiv = document.querySelector('.form-row.field-alternative_domains .readonly'); - const alternativeDomainslinks = alternativeDomainsDiv.querySelectorAll('a'); - const alternativeDomains = Array.from(alternativeDomainslinks).map(link => link.textContent); - - //------ Existing Websites - const existingWebsitesDiv = document.querySelector('.form-row.field-current_websites .readonly'); - const existingWebsiteslinks = existingWebsitesDiv.querySelectorAll('a'); - const existingWebsites = Array.from(existingWebsiteslinks).map(link => link.textContent); - - //------ Additional Contacts - // 1 - Create a hyperlinks map so we can display contact details and also link to the contact - const otherContactsDiv = document.querySelector('.form-row.field-other_contacts .readonly'); - let otherContactLinks = []; - const nameToUrlMap = {}; - if (otherContactsDiv) { - otherContactLinks = otherContactsDiv.querySelectorAll('a'); - otherContactLinks.forEach(link => { - const name = link.textContent.trim(); - const url = link.href; - nameToUrlMap[name] = url; - }); - } - - // 2 - Iterate through contact details and assemble html for summary - let otherContactsSummary = "" - // Get the table rows of contact details - // Select all contact elements - const contacts = document.querySelectorAll('.dja-detail-list dl'); - - // Iterate through each contact element - const bulletList = document.createElement('ul'); - contacts.forEach(contact => { - const name = contact.querySelector('a#contact_info_name').innerText; - const title = contact.querySelector('span#contact_info_title').innerText; - const email = contact.querySelector('span#contact_info_email').innerText; - const phone = contact.querySelector('span#contact_info_phone').innerText; - const url = nameToUrlMap[name] || '#'; - - // Format the contact information - const listItem = document.createElement('li'); - listItem.innerHTML = `${name}, ${title}, ${email}, ${phone}`; - bulletList.appendChild(listItem); - }); - otherContactsSummary += bulletList.outerHTML - - - //------ Requested Domains - const requestedDomainElement = document.getElementById('id_requested_domain'); - const requestedDomain = requestedDomainElement.options[requestedDomainElement.selectedIndex].text; - - //------ Submitter - // Function to extract text by ID and handle missing elements - function extractTextById(id, divElement) { - if (divElement) { - const element = divElement.querySelector(`#${id}`); - return element ? ", " + element.textContent.trim() : ''; - } - return ''; - } - // Extract the submitter name, title, email, and phone number - const submitterDiv = document.querySelector('.form-row.field-submitter'); - const submitterNameElement = document.getElementById('id_submitter'); - const submitterName = submitterNameElement.options[submitterNameElement.selectedIndex].text; - const submitterTitle = extractTextById('contact_info_title', submitterDiv); - const submitterEmail = extractTextById('contact_info_email', submitterDiv); - const submitterPhone = extractTextById('contact_info_phone', submitterDiv); - let submitterInfo = `${submitterName}${submitterTitle}${submitterEmail}${submitterPhone}`; - - - //------ Senior Official - const seniorOfficialDiv = document.querySelector('.form-row.field-senior_official'); - const seniorOfficialElement = document.getElementById('id_senior_official'); - const seniorOfficialName = seniorOfficialElement.options[seniorOfficialElement.selectedIndex].text; - const seniorOfficialTitle = extractTextById('contact_info_title', seniorOfficialDiv); - const seniorOfficialEmail = extractTextById('contact_info_email', seniorOfficialDiv); - const seniorOfficialPhone = extractTextById('contact_info_phone', seniorOfficialDiv); - let seniorOfficialInfo = `${seniorOfficialName}${seniorOfficialTitle}${seniorOfficialEmail}${seniorOfficialPhone}`; - - const summary = `Recommendation:
    ` + - `Organization Type: ${organizationType}
    ` + - `Requested Domain: ${requestedDomain}
    ` + - `Existing website(s): ${existingWebsites.join(', ')}
    ` + - `Rationale:
    ` + - `Alternate Domain(s): ${alternativeDomains.join(', ')}
    ` + - `Submitter: ${submitterInfo}
    ` + - `Senior Official: ${seniorOfficialInfo}
    ` + - `Additional Contact(s): ${otherContactsSummary}
    `; - - // Create a temporary element - let tempElement = document.createElement('div'); - tempElement.innerHTML = summary; - // Append the element to the body - document.body.appendChild(tempElement); - - // Use the Selection and Range APIs to select the element's content - let range = document.createRange(); - range.selectNodeContents(tempElement); - let selection = window.getSelection(); - selection.removeAllRanges(); - selection.addRange(range); - - // Use the Clipboard API to write the selected HTML content to the clipboard - navigator.clipboard.write([ - new ClipboardItem({ - 'text/html': new Blob([tempElement.innerHTML], { type: 'text/html' }) - }) - ]).then(() => { - console.log('Summary copied to clipboard successfully!'); - }).catch(err => { - console.error('Failed to copy text: ', err); - }); - document.body.removeChild(tempElement); - }); -}); diff --git a/src/registrar/assets/js/get-gov-admin.js b/src/registrar/assets/js/get-gov-admin.js index d8bc21899..fe25b2feb 100644 --- a/src/registrar/assets/js/get-gov-admin.js +++ b/src/registrar/assets/js/get-gov-admin.js @@ -207,6 +207,7 @@ function addOrRemoveSessionBoolean(name, add){ })(); + /** An IIFE for pages in DjangoAdmin that use a clipboard button */ (function (){ @@ -233,21 +234,17 @@ function addOrRemoveSessionBoolean(name, add){ buttonIcon.setAttribute('xlink:href', baseHref + '#check'); // Change the button text - nearestSpan = button.querySelector("span") + let nearestSpan = button.querySelector("span") + let original_text = nearestSpan.innerText nearestSpan.innerText = "Copied to clipboard" setTimeout(function() { // Change back to the copy icon buttonIcon.setAttribute('xlink:href', currentHref); - if (button.classList.contains('usa-button__small-text')) { - nearestSpan.innerText = "Copy email"; - } else { - nearestSpan.innerText = "Copy"; - } + nearestSpan.innerText = original_text; }, 2000); } - }).catch(function(error) { console.error('Clipboard copy failed', error); }); @@ -605,3 +602,155 @@ function initializeWidgetOnList(list, parentId) { } } })(); + + +/** An IIFE for copy summary button (appears in DomainRegistry models) +*/ +(function (){ + const copyButton = document.getElementById('copy-summary-btn'); + + if (copyButton) { + copyButton.addEventListener('click', function() { + /// Generate a rich HTML summary text and copy to clipboard + + //------ Organization Type + const organizationTypeElement = document.getElementById('id_organization_type'); + const organizationType = organizationTypeElement.options[organizationTypeElement.selectedIndex].text; + + //------ Alternative Domains + const alternativeDomainsDiv = document.querySelector('.form-row.field-alternative_domains .readonly'); + const alternativeDomainslinks = alternativeDomainsDiv.querySelectorAll('a'); + const alternativeDomains = Array.from(alternativeDomainslinks).map(link => link.textContent); + + //------ Existing Websites + const existingWebsitesDiv = document.querySelector('.form-row.field-current_websites .readonly'); + const existingWebsiteslinks = existingWebsitesDiv.querySelectorAll('a'); + const existingWebsites = Array.from(existingWebsiteslinks).map(link => link.textContent); + + //------ Additional Contacts + // 1 - Create a hyperlinks map so we can display contact details and also link to the contact + const otherContactsDiv = document.querySelector('.form-row.field-other_contacts .readonly'); + let otherContactLinks = []; + const nameToUrlMap = {}; + if (otherContactsDiv) { + otherContactLinks = otherContactsDiv.querySelectorAll('a'); + otherContactLinks.forEach(link => { + const name = link.textContent.trim(); + const url = link.href; + nameToUrlMap[name] = url; + }); + } + + // 2 - Iterate through contact details and assemble html for summary + let otherContactsSummary = "" + // Get the table rows of contact details + // Select all contact elements + const contacts = document.querySelectorAll('.dja-detail-list dl'); + + // Iterate through each contact element + const bulletList = document.createElement('ul'); + contacts.forEach(contact => { + const name = contact.querySelector('a#contact_info_name').innerText; + const title = contact.querySelector('span#contact_info_title').innerText; + const email = contact.querySelector('span#contact_info_email').innerText; + const phone = contact.querySelector('span#contact_info_phone').innerText; + const url = nameToUrlMap[name] || '#'; + + // Format the contact information + const listItem = document.createElement('li'); + listItem.innerHTML = `${name}, ${title}, ${email}, ${phone}`; + bulletList.appendChild(listItem); + }); + otherContactsSummary += bulletList.outerHTML + + + //------ Requested Domains + const requestedDomainElement = document.getElementById('id_requested_domain'); + const requestedDomain = requestedDomainElement.options[requestedDomainElement.selectedIndex].text; + + //------ Submitter + // Function to extract text by ID and handle missing elements + function extractTextById(id, divElement) { + if (divElement) { + const element = divElement.querySelector(`#${id}`); + return element ? ", " + element.textContent.trim() : ''; + } + return ''; + } + // Extract the submitter name, title, email, and phone number + const submitterDiv = document.querySelector('.form-row.field-submitter'); + const submitterNameElement = document.getElementById('id_submitter'); + const submitterName = submitterNameElement.options[submitterNameElement.selectedIndex].text; + const submitterTitle = extractTextById('contact_info_title', submitterDiv); + const submitterEmail = extractTextById('contact_info_email', submitterDiv); + const submitterPhone = extractTextById('contact_info_phone', submitterDiv); + let submitterInfo = `${submitterName}${submitterTitle}${submitterEmail}${submitterPhone}`; + + + //------ Senior Official + const seniorOfficialDiv = document.querySelector('.form-row.field-senior_official'); + const seniorOfficialElement = document.getElementById('id_senior_official'); + const seniorOfficialName = seniorOfficialElement.options[seniorOfficialElement.selectedIndex].text; + const seniorOfficialTitle = extractTextById('contact_info_title', seniorOfficialDiv); + const seniorOfficialEmail = extractTextById('contact_info_email', seniorOfficialDiv); + const seniorOfficialPhone = extractTextById('contact_info_phone', seniorOfficialDiv); + let seniorOfficialInfo = `${seniorOfficialName}${seniorOfficialTitle}${seniorOfficialEmail}${seniorOfficialPhone}`; + + const summary = `Recommendation:
    ` + + `Organization Type: ${organizationType}
    ` + + `Requested Domain: ${requestedDomain}
    ` + + `Existing website(s): ${existingWebsites.join(', ')}
    ` + + `Rationale:
    ` + + `Alternate Domain(s): ${alternativeDomains.join(', ')}
    ` + + `Submitter: ${submitterInfo}
    ` + + `Senior Official: ${seniorOfficialInfo}
    ` + + `Additional Contact(s): ${otherContactsSummary}
    `; + + // Create a temporary element + let tempElement = document.createElement('div'); + tempElement.innerHTML = summary; + // Append the element to the body + document.body.appendChild(tempElement); + + // Use the Selection and Range APIs to select the element's content + let range = document.createRange(); + range.selectNodeContents(tempElement); + let selection = window.getSelection(); + selection.removeAllRanges(); + selection.addRange(range); + + // Use the Clipboard API to write the selected HTML content to the clipboard + navigator.clipboard.write([ + new ClipboardItem({ + 'text/html': new Blob([tempElement.innerHTML], { type: 'text/html' }) + }) + ]).then(() => { + // Change the icon to a checkmark on successful copy + let buttonIcon = copyButton.querySelector('.usa-button__clipboard use'); + if (buttonIcon) { + let currentHref = buttonIcon.getAttribute('xlink:href'); + let baseHref = currentHref.split('#')[0]; + + // Append the new icon reference + buttonIcon.setAttribute('xlink:href', baseHref + '#check'); + + // Change the button text + nearestSpan = copyButton.querySelector("span") + original_text = nearestSpan.innerText + nearestSpan.innerText = "Copied to clipboard" + + setTimeout(function() { + // Change back to the copy icon + buttonIcon.setAttribute('xlink:href', currentHref); + nearestSpan.innerText = original_text + }, 2000); + + } + console.log('Summary copied to clipboard successfully!'); + }).catch(err => { + console.error('Failed to copy text: ', err); + }); + document.body.removeChild(tempElement); + }); + } +})(); \ No newline at end of file diff --git a/src/registrar/assets/sass/_theme/_buttons.scss b/src/registrar/assets/sass/_theme/_buttons.scss index 577c9ce29..d246366d8 100644 --- a/src/registrar/assets/sass/_theme/_buttons.scss +++ b/src/registrar/assets/sass/_theme/_buttons.scss @@ -128,11 +128,6 @@ a.withdraw:active { vertical-align: bottom; } -a.historylink .usa-icon { - vertical-align: middle; - margin: 0px; -} - a.usa-button--unstyled:visited { color: color('primary'); } @@ -218,4 +213,4 @@ a.usa-button--unstyled:visited { .margin-right-neg-4px { margin-right: -4px; -} +} \ No newline at end of file diff --git a/src/registrar/assets/sass/_theme/_links.scss b/src/registrar/assets/sass/_theme/_links.scss index e9b71733a..35546face 100644 --- a/src/registrar/assets/sass/_theme/_links.scss +++ b/src/registrar/assets/sass/_theme/_links.scss @@ -15,3 +15,8 @@ margin-right: units(0.5); } } + +.modelLink-icon { + margin-bottom: 2px; + vertical-align: middle; +} \ No newline at end of file diff --git a/src/registrar/templates/admin/change_form.html b/src/registrar/templates/admin/change_form.html index 3efbe554e..f2ac7f2df 100644 --- a/src/registrar/templates/admin/change_form.html +++ b/src/registrar/templates/admin/change_form.html @@ -10,8 +10,4 @@ {% endblock %} {% endif %} -{% endblock %} - -{% block extrahead %} - {% endblock %} \ No newline at end of file diff --git a/src/registrar/templates/admin/change_form_object_tools.html b/src/registrar/templates/admin/change_form_object_tools.html index 03c519241..ec50f493a 100644 --- a/src/registrar/templates/admin/change_form_object_tools.html +++ b/src/registrar/templates/admin/change_form_object_tools.html @@ -16,12 +16,12 @@ {% else %}