diff --git a/src/registrar/assets/js/uswds-edited.js b/src/registrar/assets/js/uswds-edited.js index e73f3b6c0..52dc441fc 100644 --- a/src/registrar/assets/js/uswds-edited.js +++ b/src/registrar/assets/js/uswds-edited.js @@ -25,6 +25,8 @@ /** * Edits made for dotgov project: * - tooltip exposed to window to be accessible in other js files + * - tooltip positioning logic updated to allow position:fixed + * - tooltip dynamic content updated to include nested element (for better sizing control) * - modal exposed to window to be accessible in other js files * - fixed bug in createHeaderButton which added newlines to header button tooltips */ @@ -5938,6 +5940,22 @@ const showToolTip = (tooltipBody, tooltipTrigger, position) => { return offset; }; + // ---- DOTGOV EDIT (Added section) + // DOTGOV: Tooltip positioning logic updated to allow position:fixed + const tooltipStyle = window.getComputedStyle(tooltipBody); + const tooltipIsFixedPositioned = tooltipStyle.position === 'fixed'; + const triggerRect = tooltipTrigger.getBoundingClientRect(); //detect if tooltip is set to "fixed" position + const targetLeft = tooltipIsFixedPositioned ? triggerRect.left + triggerRect.width/2 + 'px': `50%` + const targetTop = tooltipIsFixedPositioned ? triggerRect.top + triggerRect.height/2 + 'px': `50%` + if (tooltipIsFixedPositioned) { + /* DOTGOV: Add listener to handle scrolling if tooltip position = 'fixed' + (so that the tooltip doesn't appear to stick to the screen) */ + window.addEventListener('scroll', function() { + findBestPosition(tooltipBody) + }); + } + // ---- END DOTGOV EDIT + /** * Positions tooltip at the top * @param {HTMLElement} e - this is the tooltip body @@ -5949,8 +5967,16 @@ const showToolTip = (tooltipBody, tooltipTrigger, position) => { const topMargin = calculateMarginOffset("top", e.offsetHeight, tooltipTrigger); const leftMargin = calculateMarginOffset("left", e.offsetWidth, tooltipTrigger); setPositionClass("top"); - e.style.left = `50%`; // center the element - e.style.top = `-${TRIANGLE_SIZE}px`; // consider the pseudo element + + // ---- DOTGOV EDIT + // e.style.left = `50%`; // center the element + // e.style.top = `-${TRIANGLE_SIZE}px`; // consider the pseudo element + + // DOTGOV: updated logic for position:fixed + e.style.left = targetLeft; // center the element + e.style.top = tooltipIsFixedPositioned ?`${triggerRect.top-TRIANGLE_SIZE}px`:`-${TRIANGLE_SIZE}px`; // consider the pseudo element + // ---- END DOTGOV EDIT + // apply our margins based on the offset e.style.margin = `-${topMargin}px 0 0 -${leftMargin / 2}px`; }; @@ -5963,7 +5989,17 @@ const showToolTip = (tooltipBody, tooltipTrigger, position) => { resetPositionStyles(e); const leftMargin = calculateMarginOffset("left", e.offsetWidth, tooltipTrigger); setPositionClass("bottom"); - e.style.left = `50%`; + + // ---- DOTGOV EDIT + // e.style.left = `50%`; + + // DOTGOV: updated logic for position:fixed + if (tooltipIsFixedPositioned){ + e.style.top = triggerRect.bottom+'px'; + } + // ---- END DOTGOV EDIT + + e.style.left = targetLeft; e.style.margin = `${TRIANGLE_SIZE}px 0 0 -${leftMargin / 2}px`; }; @@ -5975,8 +6011,16 @@ const showToolTip = (tooltipBody, tooltipTrigger, position) => { resetPositionStyles(e); const topMargin = calculateMarginOffset("top", e.offsetHeight, tooltipTrigger); setPositionClass("right"); - e.style.top = `50%`; - e.style.left = `${tooltipTrigger.offsetLeft + tooltipTrigger.offsetWidth + TRIANGLE_SIZE}px`; + + // ---- DOTGOV EDIT + // e.style.top = `50%`; + // e.style.left = `${tooltipTrigger.offsetLeft + tooltipTrigger.offsetWidth + TRIANGLE_SIZE}px`; + + // DOTGOV: updated logic for position:fixed + e.style.top = targetTop; + e.style.left = tooltipIsFixedPositioned ? `${triggerRect.right + TRIANGLE_SIZE}px`:`${tooltipTrigger.offsetLeft + tooltipTrigger.offsetWidth + TRIANGLE_SIZE}px`; + // ---- END DOTGOV EDIT + e.style.margin = `-${topMargin / 2}px 0 0 0`; }; @@ -5991,8 +6035,16 @@ const showToolTip = (tooltipBody, tooltipTrigger, position) => { // we have to check for some utility margins const leftMargin = calculateMarginOffset("left", tooltipTrigger.offsetLeft > e.offsetWidth ? tooltipTrigger.offsetLeft - e.offsetWidth : e.offsetWidth, tooltipTrigger); setPositionClass("left"); - e.style.top = `50%`; - e.style.left = `-${TRIANGLE_SIZE}px`; + + // ---- DOTGOV EDIT + // e.style.top = `50%`; + // e.style.left = `-${TRIANGLE_SIZE}px`; + + // DOTGOV: updated logic for position:fixed + e.style.top = targetTop; + e.style.left = tooltipIsFixedPositioned ? `${triggerRect.left-TRIANGLE_SIZE}px` : `-${TRIANGLE_SIZE}px`; + // ---- END DOTGOV EDIT + e.style.margin = `-${topMargin / 2}px 0 0 ${tooltipTrigger.offsetLeft > e.offsetWidth ? leftMargin : -leftMargin}px`; // adjust the margin }; @@ -6017,6 +6069,7 @@ const showToolTip = (tooltipBody, tooltipTrigger, position) => { if (i < positions.length) { const pos = positions[i]; pos(element); + if (!isElementInViewport(element)) { // eslint-disable-next-line no-param-reassign tryPositions(i += 1); @@ -6128,7 +6181,17 @@ const setUpAttributes = tooltipTrigger => { tooltipBody.setAttribute("aria-hidden", "true"); // place the text in the tooltip - tooltipBody.textContent = tooltipContent; + + // -- DOTGOV EDIT + // tooltipBody.textContent = tooltipContent; + + // DOTGOV: nest the text element to allow us greater control over width and wrapping behavior + tooltipBody.innerHTML = ` + + ${tooltipContent} + ` + // -- END DOTGOV EDIT + return { tooltipBody, position, diff --git a/src/registrar/assets/sass/_theme/_tooltips.scss b/src/registrar/assets/sass/_theme/_tooltips.scss index 3ab630dc0..58beb8ae6 100644 --- a/src/registrar/assets/sass/_theme/_tooltips.scss +++ b/src/registrar/assets/sass/_theme/_tooltips.scss @@ -28,3 +28,47 @@ #extended-logo .usa-tooltip__body { font-weight: 400 !important; } + +.domains__table { + /* + Trick tooltips in the domains table to do 2 things... + 1 - Shrink itself to a padded viewport window + (override width and wrapping properties in key areas to constrain tooltip size) + 2 - NOT be clipped by the table's scrollable view + (Set tooltip position to "fixed", which prevents tooltip from being clipped by parent + containers. Fixed-position detection was added to uswds positioning logic to update positioning + calculations accordingly.) + */ + .usa-tooltip__body { + white-space: inherit; + max-width: fit-content; // prevent adjusted widths from being larger than content + position: fixed; // prevents clipping by parent containers + } + /* + Override width adustments in this dynamically added class + (this is original to the javascript handler as a way to shrink tooltip contents within the viewport, + but is insufficient for our needs. We cannot simply override its properties + because the logic surrounding its dynamic appearance in the DOM does not account + for parent containers (basically, this class isn't in the DOM when we need it). + Intercept .usa-tooltip__content instead and nullify the effects of + .usa-tooltip__body--wrap to prevent conflicts) + */ + .usa-tooltip__body--wrap { + min-width: inherit; + width: inherit; + } + /* + Add width and wrapping to tooltip content in order to confine it to a smaller viewport window. + */ + .usa-tooltip__content { + width: 50vw; + text-wrap: wrap; + text-align: center; + font-size: inherit; //inherit tooltip fontsize of .93rem + max-width: fit-content; + @include at-media('desktop') { + width: 70vw; + } + display: block; + } +} \ No newline at end of file diff --git a/src/registrar/templates/domain_detail.html b/src/registrar/templates/domain_detail.html index dca68f6ef..0fb29d2eb 100644 --- a/src/registrar/templates/domain_detail.html +++ b/src/registrar/templates/domain_detail.html @@ -45,7 +45,7 @@

{{ domain.name }}

- To manage information for this domain, you must add yourself as a domain manager. + You don't have access to manage {{domain.name}}. If you need to make updates, contact one of the listed domain managers.

diff --git a/src/registrar/tests/test_views_domain.py b/src/registrar/tests/test_views_domain.py index 127b78a4a..e35d38b32 100644 --- a/src/registrar/tests/test_views_domain.py +++ b/src/registrar/tests/test_views_domain.py @@ -340,7 +340,10 @@ def test_domain_readonly_on_detail_page(self): detail_page = self.client.get(f"/domain/{domain.id}") # Check that alert message displays properly self.assertContains( - detail_page, "To manage information for this domain, you must add yourself as a domain manager." + detail_page, + "You don't have access to manage " + + domain.name + + ". If you need to make updates, contact one of the listed domain managers.", ) # Check that user does not have option to Edit domain self.assertNotContains(detail_page, "Edit")