diff --git a/static/css/styles.css b/static/css/styles.css index c2540e67a..34a9800dd 100644 --- a/static/css/styles.css +++ b/static/css/styles.css @@ -4386,7 +4386,7 @@ html.dark-theme body main .feedback-wrapper .feedback-modal a { text-decoration: none; } -.documentation h1:hover > a.anchor-link, .documentation h2:hover > a.anchor-link, .documentation h3:hover > a.anchor-link, .documentation h4:hover > a.anchor-link { +.documentation h1:hover > a.anchor-link, .documentation h2:hover > a.anchor-link, .documentation h3:hover > a.anchor-link, .documentation h4:hover > a.anchor-link, .documentation tr:hover > a.anchor-link { opacity: 1; } @@ -4398,6 +4398,14 @@ html.dark-theme body main .feedback-wrapper .feedback-modal a { content: none; } +.documentation tr { + overflow-x: hidden; +} + +.documentation tr a.anchor-link { + position: absolute; +} + .documentation aside.menu { padding-bottom: 7.5rem; } diff --git a/static/js/main.js b/static/js/main.js index fa3786fe3..a3844e823 100644 --- a/static/js/main.js +++ b/static/js/main.js @@ -1107,26 +1107,42 @@ const addCopyButtons = (clipboard)=>{ pre.appendChild(button); }); }; -const addAnchorLinks = ()=>{ - document.querySelectorAll(".content h1, .content h2, .content h3, .content h4").forEach((heading)=>{ - let id = heading.innerText.toLowerCase().replace(/[`~!@#$%^&*()_|+=?;:'",.<>\{\}\[\]\\\/]/gi, "").replace(/ +/g, "-"); - heading.setAttribute("id", id); - heading.classList.add("heading-anchor"); - let anchor = document.createElement("a"); - anchor.className = "anchor-link"; - anchor.href = "#" + id; - anchor.innerHTML = ''; - heading.append(anchor); - anchor.addEventListener("click", (e)=>{ +const addAnchorLinks = () => { + const elementsToProcess = document.querySelectorAll(".content h1, .content h2, .content h3, .content h4, .content tr"); + + elementsToProcess.forEach(element => { + let uniqueId; + if (element.tagName.toLowerCase() === 'tr') { + const closestHeading = element.closest('.content').querySelector('.heading-anchor'); + const rowText = Array.from(element.cells).map(cell => cell.textContent.trim()).join(' ').toLowerCase().replace(/[^\w\s-]/g, '').replace(/\s+/g, '-'); + + if (closestHeading) { + const headingText = closestHeading.textContent.trim().toLowerCase().replace(/[^\w\s-]/g, '').replace(/\s+/g, '-'); + uniqueId = `${headingText}-${rowText}`; + } else { + uniqueId = rowText; + } + } else { + uniqueId = element.textContent.trim().toLowerCase().replace(/[^\w\s-]/g, '').replace(/\s+/g, '-'); + } + + element.classList.add("heading-anchor"); + element.setAttribute('id', uniqueId); + let anchor = document.createElement('a'); + anchor.className = 'anchor-link'; + anchor.href = '#' + uniqueId; + anchor.innerHTML = ''; + element.append(anchor); + anchor.addEventListener("click", (e) => { e.preventDefault(); window.location = anchor.href; - document.querySelector(anchor.getAttribute("href")).scrollIntoView({ - behavior: "smooth", - block: "start" //scroll to top of the target element - }); - }); - }); -}; + document.querySelector(anchor.getAttribute('href')).scrollIntoView({ + behavior: 'smooth', + block: 'start' + }) + }) + }) +} function removeExpiredEvents() { let events = document.querySelectorAll(".community-highlight .carousel-cell"); let eventsNumber = events.length; diff --git a/static/js/src/modules/utils.js b/static/js/src/modules/utils.js index ed3324950..bc3b41a72 100644 --- a/static/js/src/modules/utils.js +++ b/static/js/src/modules/utils.js @@ -82,23 +82,37 @@ const addCopyButtons = (clipboard) => { }; const addAnchorLinks = () => { - document.querySelectorAll(".content h1, .content h2, .content h3, .content h4").forEach(heading => { - let id = heading.innerText.toLowerCase() - .replace(/[`~!@#$%^&*()_|+=?;:'",.<>\{\}\[\]\\\/]/gi, '') - .replace(/ +/g, '-'); - heading.setAttribute("id", id); - heading.classList.add("heading-anchor"); + const elementsToProcess = document.querySelectorAll(".content h1, .content h2, .content h3, .content h4, .content tr"); + + elementsToProcess.forEach(element => { + let uniqueId; + if (element.tagName.toLowerCase() === 'tr') { + const closestHeading = element.closest('.content').querySelector('.heading-anchor'); + const rowText = Array.from(element.cells).map(cell => cell.textContent.trim()).join(' ').toLowerCase().replace(/[^\w\s-]/g, '').replace(/\s+/g, '-'); + + if (closestHeading) { + const headingText = closestHeading.textContent.trim().toLowerCase().replace(/[^\w\s-]/g, '').replace(/\s+/g, '-'); + uniqueId = `${headingText}-${rowText}`; + } else { + uniqueId = rowText; + } + } else { + uniqueId = element.textContent.trim().toLowerCase().replace(/[^\w\s-]/g, '').replace(/\s+/g, '-'); + } + + element.classList.add("heading-anchor"); + element.setAttribute('id', uniqueId); let anchor = document.createElement('a'); anchor.className = 'anchor-link'; - anchor.href = '#' + id; - anchor.innerHTML = ''; - heading.append(anchor); + anchor.href = '#' + uniqueId; + anchor.innerHTML = ''; + element.append(anchor); anchor.addEventListener("click", (e) => { - e.preventDefault() - window.location = anchor.href + e.preventDefault(); + window.location = anchor.href; document.querySelector(anchor.getAttribute('href')).scrollIntoView({ behavior: 'smooth', - block: 'start' //scroll to top of the target element + block: 'start' }) }) }) diff --git a/static/sass/styles.scss b/static/sass/styles.scss index bcc3a1ce8..a47339b7b 100644 --- a/static/sass/styles.scss +++ b/static/sass/styles.scss @@ -409,6 +409,13 @@ Importing color and theme updates for the brand 1.5 refresh } } } + tr { + &:hover { + >a.anchor-link { + opacity: 1; + } + } + } a { font-weight: 600; @@ -419,6 +426,13 @@ Importing color and theme updates for the brand 1.5 refresh content: none; } } + + tr { + overflow-x: hidden; + a.anchor-link { + position: absolute; + } + } aside.menu { padding-bottom: 7.5rem;