Implement flattened structure with in-page navigation and back-to-top links
This commit is contained in:
@@ -1 +1,164 @@
|
||||
|
||||
// Custom JavaScript for IT Learning Notes
|
||||
|
||||
// Wait for the DOM to be fully loaded
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Improve anchor link scrolling behavior
|
||||
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
||||
anchor.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
const targetId = this.getAttribute('href');
|
||||
|
||||
// Only process internal page links
|
||||
if (targetId.startsWith('#')) {
|
||||
const targetElement = document.querySelector(targetId);
|
||||
|
||||
if (targetElement) {
|
||||
// Smooth scroll to the target
|
||||
window.scrollTo({
|
||||
top: targetElement.offsetTop - 60, // Account for header/navigation
|
||||
behavior: 'smooth'
|
||||
});
|
||||
|
||||
// Update URL without reloading the page
|
||||
history.pushState(null, null, targetId);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Add "Back to Top" links if they don't exist in the content
|
||||
const sections = document.querySelectorAll('h2');
|
||||
sections.forEach(section => {
|
||||
// Check if there's already a back-to-top link after this section
|
||||
const nextElement = section.nextElementSibling;
|
||||
const hasBackToTop = false;
|
||||
|
||||
// Find the end of this section (next h2 or end of document)
|
||||
let currentElement = section.nextElementSibling;
|
||||
while (currentElement && currentElement.tagName !== 'H2') {
|
||||
if (currentElement.tagName === 'A' &&
|
||||
currentElement.getAttribute('href') &&
|
||||
currentElement.getAttribute('href').includes('top')) {
|
||||
hasBackToTop = true;
|
||||
break;
|
||||
}
|
||||
currentElement = currentElement.nextElementSibling;
|
||||
}
|
||||
|
||||
// Add back-to-top link if needed
|
||||
if (!hasBackToTop && currentElement && currentElement.tagName === 'H2') {
|
||||
const backToTop = document.createElement('a');
|
||||
backToTop.href = '#';
|
||||
backToTop.textContent = 'Back to Top';
|
||||
backToTop.className = 'back-to-top';
|
||||
backToTop.style.display = 'block';
|
||||
backToTop.style.marginBottom = '2em';
|
||||
|
||||
// Insert before the next heading
|
||||
section.parentNode.insertBefore(backToTop, currentElement);
|
||||
}
|
||||
});
|
||||
|
||||
// Fix for any dynamically loaded content
|
||||
setTimeout(function() {
|
||||
// Force redraw of content area
|
||||
const content = document.querySelector('.content');
|
||||
if (content) {
|
||||
content.style.display = 'none';
|
||||
content.offsetHeight; // Force reflow
|
||||
content.style.display = 'block';
|
||||
}
|
||||
|
||||
// Scroll to anchor if present in URL
|
||||
if (window.location.hash) {
|
||||
const element = document.getElementById(window.location.hash.substring(1));
|
||||
if (element) {
|
||||
element.scrollIntoView({behavior: 'smooth'});
|
||||
}
|
||||
}
|
||||
}, 100);
|
||||
});
|
||||
|
||||
// Create a table of contents if it doesn't exist
|
||||
function generateTableOfContents() {
|
||||
// Only run if we don't have a TOC div already
|
||||
if (!document.querySelector('.toc')) {
|
||||
const headings = document.querySelectorAll('h2');
|
||||
if (headings.length > 2) { // Only if we have a reasonable number of headings
|
||||
const toc = document.createElement('div');
|
||||
toc.className = 'toc';
|
||||
|
||||
const tocTitle = document.createElement('h2');
|
||||
tocTitle.textContent = 'Table of Contents';
|
||||
toc.appendChild(tocTitle);
|
||||
|
||||
const tocList = document.createElement('ul');
|
||||
|
||||
headings.forEach(heading => {
|
||||
if (!heading.textContent.toLowerCase().includes('table of contents')) {
|
||||
const listItem = document.createElement('li');
|
||||
const link = document.createElement('a');
|
||||
|
||||
// Create an id for the heading if it doesn't have one
|
||||
if (!heading.id) {
|
||||
heading.id = heading.textContent.toLowerCase()
|
||||
.replace(/[^\w]+/g, '-');
|
||||
}
|
||||
|
||||
link.href = '#' + heading.id;
|
||||
link.textContent = heading.textContent;
|
||||
|
||||
listItem.appendChild(link);
|
||||
tocList.appendChild(listItem);
|
||||
}
|
||||
});
|
||||
|
||||
toc.appendChild(tocList);
|
||||
|
||||
// Insert after the first heading (title)
|
||||
const title = document.querySelector('h1');
|
||||
if (title && title.nextElementSibling) {
|
||||
title.parentNode.insertBefore(toc, title.nextElementSibling.nextElementSibling);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run when the page loads
|
||||
window.addEventListener('load', function() {
|
||||
// Generate TOC if needed
|
||||
generateTableOfContents();
|
||||
|
||||
// Enable all sections that might have been hidden
|
||||
document.querySelectorAll('.content-hidden')
|
||||
.forEach(el => el.classList.remove('content-hidden'));
|
||||
});
|
||||
|
||||
// Monitor for any dynamically added elements and ensure they're visible
|
||||
const observer = new MutationObserver(function(mutations) {
|
||||
mutations.forEach(function(mutation) {
|
||||
if (mutation.addedNodes && mutation.addedNodes.length > 0) {
|
||||
for (let i = 0; i < mutation.addedNodes.length; i++) {
|
||||
const node = mutation.addedNodes[i];
|
||||
if (node.nodeType === 1) { // Element node
|
||||
if (node.classList && (
|
||||
node.classList.contains('section') ||
|
||||
node.classList.contains('content') ||
|
||||
node.classList.contains('content-hidden')
|
||||
)) {
|
||||
node.style.display = 'block';
|
||||
node.style.visibility = 'visible';
|
||||
node.style.opacity = '1';
|
||||
node.classList.remove('content-hidden');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Start observing the document body for changes
|
||||
observer.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
Reference in New Issue
Block a user