table-of-content
Advanced tools
Comparing version
143
index.js
function initTableOfContents() { | ||
let tocButton = document.getElementById('toc-button'); | ||
if (!tocButton) { | ||
tocButton = document.createElement('button'); | ||
tocButton.id = 'toc-button'; | ||
tocButton.title = 'Xem mục lục.'; | ||
tocButton.className = 'fixed w-10 h-10 bottom-[100px] bg-primary rounded-full cursor-pointer hidden shadow-md'; | ||
document.body.appendChild(tocButton); | ||
let index = document.getElementById('index'); | ||
if (!index) { | ||
index = document.createElement('div'); | ||
index.id = 'index'; | ||
index.className = 'max-w-3xl mx-auto'; | ||
document.body.appendChild(index); | ||
} | ||
let tocContent = document.getElementById('toc-content'); | ||
if (!tocContent) { | ||
tocContent = document.createElement('div'); | ||
tocContent.id = 'toc-content'; | ||
document.body.appendChild(tocContent); | ||
} | ||
const styleSheet = document.createElement('style'); | ||
styleSheet.textContent = ` | ||
#toc-button { | ||
width: 40px; | ||
height: 40px; | ||
z-index: 2; | ||
} | ||
#toc-content { | ||
position: fixed; | ||
bottom: 150px; | ||
width: 350px; | ||
height: 500px; | ||
z-index: 2; | ||
overflow-y: auto; | ||
background-color: white; | ||
padding: 10px; | ||
border-radius: 10px; | ||
display: none; | ||
scrollbar-width: none; | ||
-ms-overflow-style: none; | ||
} | ||
#toc-content::-webkit-scrollbar { | ||
display: none; | ||
} | ||
`; | ||
document.head.appendChild(styleSheet); | ||
const contentElement = document.querySelector('.prose'); | ||
const headings = document.querySelectorAll('h2, h3, h4'); | ||
if (headings.length > 0) { | ||
const tocList = document.createElement('ul'); | ||
const tocList = document.createElement('ul'); | ||
let currentParent = null; | ||
let visibleHeadings = Math.max(0, headings.length - 20); | ||
headings.forEach((heading) => { | ||
const listItem = document.createElement('li'); | ||
const anchor = document.createElement('a'); | ||
anchor.href = `#${heading.id}`; | ||
anchor.textContent = heading.textContent; | ||
listItem.appendChild(anchor); | ||
for (let i = 0; i < visibleHeadings; i++) { | ||
const heading = headings[i]; | ||
const listItem = document.createElement('li'); | ||
const anchor = document.createElement('a'); | ||
anchor.href = `#${heading.id}`; | ||
anchor.textContent = heading.textContent; | ||
switch (heading.tagName.toLowerCase()) { | ||
case 'h2': | ||
break; | ||
case 'h3': | ||
listItem.style.fontStyle = 'italic'; | ||
break; | ||
case 'h4': | ||
break; | ||
} | ||
listItem.appendChild(anchor); | ||
if (heading.tagName.toLowerCase() === 'h3' || heading.tagName.toLowerCase() === 'h4') { | ||
if (currentParent) { | ||
const subList = currentParent.querySelector('ul') || document.createElement('ul'); | ||
subList.appendChild(listItem); | ||
currentParent.appendChild(subList); | ||
} | ||
} else { | ||
tocList.appendChild(listItem); | ||
currentParent = listItem; | ||
} | ||
}); | ||
tocContent.appendChild(tocList); | ||
index.appendChild(tocList); | ||
function checkContentVisibility() { | ||
if (!contentElement) return false; | ||
const rect = contentElement.getBoundingClientRect(); | ||
return ( | ||
rect.top < window.innerHeight && | ||
rect.bottom > 0 && | ||
rect.top < 0 && | ||
rect.bottom > 500 | ||
); | ||
} | ||
hideLastTOCItems(tocList, 20); | ||
window.addEventListener('scroll', function () { | ||
if (checkContentVisibility()) { | ||
tocButton.style.display = 'block'; | ||
} else { | ||
tocButton.style.display = 'none'; | ||
tocContent.style.display = 'none'; | ||
} | ||
}); | ||
function hideLastTOCItems(tocList, count) { | ||
const items = tocList.querySelectorAll('li'); | ||
const totalItems = items.length; | ||
setTimeout(() => window.dispatchEvent(new Event('scroll')), 100); | ||
const itemsToHide = Math.min(count, totalItems); | ||
let tocVisible = false; | ||
tocButton.addEventListener('click', function () { | ||
tocVisible = !tocVisible; | ||
tocContent.style.display = tocVisible ? 'block' : 'none'; | ||
}); | ||
document.addEventListener('click', function (e) { | ||
if ( | ||
tocVisible && | ||
e.target !== tocButton && | ||
!tocContent.contains(e.target) | ||
) { | ||
tocVisible = false; | ||
tocContent.style.display = 'none'; | ||
} | ||
}); | ||
for (let i = totalItems - itemsToHide; i < totalItems; i++) { | ||
items[i].style.display = 'none'; | ||
} | ||
} | ||
function destroy() { | ||
window.removeEventListener('scroll', null); | ||
tocButton.removeEventListener('click', null); | ||
document.removeEventListener('click', null); | ||
if (tocButton && tocButton.parentNode) { | ||
tocButton.parentNode.removeChild(tocButton); | ||
if (index && index.parentNode) { | ||
index.parentNode.removeChild(index); | ||
} | ||
if (tocContent && tocContent.parentNode) { | ||
tocContent.parentNode.removeChild(tocContent); | ||
} | ||
} | ||
@@ -122,6 +69,6 @@ | ||
document.addEventListener('DOMContentLoaded', () => { | ||
window.onload = () => { | ||
initTableOfContents(); | ||
}); | ||
}; | ||
module.exports = { initTableOfContents }; |
{ | ||
"name": "table-of-content", | ||
"version": "1.0.2", | ||
"version": "1.0.3", | ||
"description": "Table of Contents Generator is a JavaScript package that creates a floating table of contents (TOC) button and panel for web pages.", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
20917
-6.82%57
-46.73%