/** * AKSRT Page Template * * Handles template-scoped content interactions: TOC, lightbox, * expandable article bodies, and one-shot query cleanup banners. * * @package AKSRT */ (function () { 'use strict'; function slugifyHeading(text) { return 'heading-' + String(text || '') .trim() .toLowerCase() .replace(/\s+/g, '-') .replace(/[^\w\u4e00-\u9fff-]/g, ''); } function initPostToc() { // Accept either explicit data-aksrt-toc="1" or any [data-nav] article body. var content = document.querySelector('.wp-posts-content[data-nav="posts"][data-aksrt-toc="1"]') || document.querySelector('.wp-posts-content[data-nav]') || document.querySelector('[data-nav="posts"]') || document.querySelector('[data-nav]'); // The article sidebar and mobile drawer share one built-in TOC source. var tocWidgets = Array.prototype.slice.call( document.querySelectorAll('.posts-nav-box.toc-widget') ); var tocLists = []; tocWidgets.forEach(function (box) { if (!box.classList.contains('toc-widget')) { box.classList.add('toc-widget'); } var list = box.querySelector('.toc-list'); if (!list) { list = document.createElement('ol'); list.className = 'toc-list'; box.appendChild(list); } tocLists.push(list); }); var mobileToggle = document.querySelector('.toc-float-btn'); var drawer = document.querySelector('.toc-drawer'); var overlay = document.querySelector('.toc-drawer-overlay'); var drawerList = drawer ? drawer.querySelector('.toc-list') : null; var closeBtn = drawer ? drawer.querySelector('.toc-drawer__close') : null; if (!content || content.dataset.aksrtTocBound === '1') return; if (!tocLists.length && !drawerList && !mobileToggle) return; content.dataset.aksrtTocBound = '1'; var maxDepth = parseInt(content.dataset.aksrtTocDepth || '3', 10) || 3; // zibll section-navs: only fill when heading count > 2 (≥3). var MIN_HEADINGS = 3; function getHeadings() { // zibll scans h1–h4 inside [data-nav]; depth setting still caps lower levels. return Array.prototype.slice.call(content.querySelectorAll('h1, h2, h3, h4')).filter(function (heading) { if (heading.closest('.no-nav') || heading.classList.contains('item-heading')) { return false; } var level = parseInt((heading.tagName || 'H2').replace('H', ''), 10) || 2; // toc_depth is typically 2–4 meaning deepest heading level from h2 baseline; // allow h1 always, then h2..h(1+maxDepth) capped at h4. if (level === 1) return true; return level <= Math.min(4, maxDepth + 1); }); } function buildToc(container) { if (!container) return false; var headings = getHeadings(); if (headings.length < MIN_HEADINGS) return false; var html = ''; headings.forEach(function (heading) { if (!heading.id) { heading.id = slugifyHeading(heading.textContent); } var levelClass = ''; if (heading.tagName === 'H1') { levelClass = 'toc-h1'; } else if (heading.tagName === 'H3') { levelClass = 'toc-h3'; } else if (heading.tagName === 'H4') { levelClass = 'toc-h4'; } html += '' + heading.textContent.trim() + ''; }); container.innerHTML = html; return true; } var hasToc = false; tocLists.forEach(function (list) { if (buildToc(list)) hasToc = true; }); if (drawerList && tocLists.indexOf(drawerList) === -1) { if (buildToc(drawerList)) hasToc = true; } if (!hasToc) { tocWidgets.forEach(function (box) { var widget = box.closest('.widget'); // A built-in TOC is a direct child of the article sidebar. Its parent // is therefore not widget chrome and must never be removed here. if (widget && widget !== document.body && widget.querySelectorAll('.posts-nav-box').length <= 1) { widget.remove(); } else { box.remove(); } }); if (mobileToggle) mobileToggle.remove(); if (drawer) drawer.remove(); if (overlay) overlay.remove(); return; } function closeDrawer() { if (drawer) drawer.classList.remove('is-open'); if (overlay) overlay.classList.remove('is-open'); document.body.style.overflow = ''; } function openDrawer() { if (drawer) drawer.classList.add('is-open'); if (overlay) overlay.classList.add('is-open'); document.body.style.overflow = 'hidden'; } function trackActiveHeading() { var headings = content.querySelectorAll('h1[id], h2[id], h3[id], h4[id]'); if (!headings.length) return; var activeId = ''; var fromTop = window.scrollY + 120; for (var i = headings.length - 1; i >= 0; i -= 1) { if (headings[i].offsetTop <= fromTop) { activeId = headings[i].id; break; } } document.querySelectorAll('.toc-list a').forEach(function (link) { link.classList.toggle('is-active', link.getAttribute('href') === '#' + activeId); }); } document.querySelectorAll('.toc-list a').forEach(function (link) { link.addEventListener('click', function (event) { var target = document.querySelector(link.getAttribute('href')); if (!target) return; event.preventDefault(); var top = target.getBoundingClientRect().top + window.pageYOffset - 105; window.scrollTo({ top: Math.max(0, top), behavior: 'smooth' }); closeDrawer(); }); }); if (mobileToggle) mobileToggle.addEventListener('click', openDrawer); if (overlay) overlay.addEventListener('click', closeDrawer); if (closeBtn) closeBtn.addEventListener('click', closeDrawer); window.addEventListener('scroll', trackActiveHeading, { passive: true }); trackActiveHeading(); } function initLightbox() { var overlay = document.getElementById('lightbox-overlay'); var content = document.querySelector(".wp-posts-content[data-aksrt-lightbox='1'], .entry-content[data-aksrt-lightbox='1']"); if (!overlay || !content || overlay.dataset.aksrtLightboxBound === '1') return; overlay.dataset.aksrtLightboxBound = '1'; var image = overlay.querySelector('.lightbox-img'); var caption = overlay.querySelector('.lightbox-caption'); var closeBtn = overlay.querySelector('.lightbox-close'); function close() { overlay.classList.remove('is-open'); overlay.setAttribute('aria-hidden', 'true'); document.body.style.overflow = ''; if (image) { image.src = ''; image.alt = ''; } } content.querySelectorAll('img').forEach(function (img) { var link = img.closest('a[href]'); var linkHref = link ? link.href : ''; var linksToImage = /\.(?:avif|gif|jpe?g|png|svg|webp)(?:[?#].*)?$/i.test(linkHref); if (img.closest('[data-no-lightbox]') || (link && !linksToImage)) return; img.classList.add('aksrt-lightbox-target'); img.addEventListener('click', function (event) { if (!image) return; if (linksToImage) event.preventDefault(); image.src = linksToImage ? linkHref : (img.getAttribute('data-src') || img.getAttribute('data-lazy-src') || img.currentSrc || img.src); image.alt = img.alt || ''; if (caption) { var figure = img.closest('figure'); var figureCaption = figure ? figure.querySelector('figcaption') : null; caption.textContent = img.alt || (figureCaption ? figureCaption.textContent : '') || ''; } overlay.classList.add('is-open'); overlay.setAttribute('aria-hidden', 'false'); document.body.style.overflow = 'hidden'; if (closeBtn) closeBtn.focus(); }); }); overlay.addEventListener('click', function (event) { if (event.target === overlay || event.target === closeBtn || (event.target.closest && event.target.closest('.lightbox-close'))) { close(); } }); document.addEventListener('keydown', function (event) { if (event.key === 'Escape' && overlay.classList.contains('is-open')) { close(); } }); } function initContentExpand() { // Zibll-style: inject .read-more inside .limit-height and expand on click. document.querySelectorAll('.wp-posts-content.limit-height, .limit-height[data-nav]').forEach(function (content) { if (content.dataset.aksrtExpandBound === '1') return; content.dataset.aksrtExpandBound = '1'; var customMax = parseInt(content.getAttribute('data-maxheight') || content.dataset.maxheight || '0', 10); // data-maxheight may be maxheight-80 (Zibll) or absolute maxheight; prefer style max-height. var styleMax = 0; if (content.style && content.style.maxHeight) { styleMax = parseInt(content.style.maxHeight, 10) || 0; } var limit = styleMax > 0 ? styleMax : (customMax > 0 ? customMax + 80 : 0); if (!(limit > 0) && customMax > 0) { limit = customMax; } if (!(limit > 0)) { content.classList.remove('limit-height'); return; } if (content.scrollHeight <= limit + 40) { content.classList.remove('limit-height'); content.style.maxHeight = ''; return; } content.classList.add('limit-height'); content.style.maxHeight = limit + 'px'; if (content.querySelector('.read-more')) return; var wrap = document.createElement('div'); wrap.className = 'read-more'; var link = document.createElement('a'); link.href = 'javascript:;'; link.className = 'read-more-open'; link.innerHTML = '展开阅读全文'; wrap.appendChild(link); content.appendChild(wrap); link.addEventListener('click', function (event) { event.preventDefault(); content.classList.remove('limit-height'); content.style.maxHeight = ''; wrap.remove(); }); }); // Compatibility: old external expand buttons. document.addEventListener('click', function (event) { var open = event.target.closest && event.target.closest('.read-more-open'); if (!open) return; var limitBox = open.closest('.limit-height'); if (!limitBox) return; event.preventDefault(); limitBox.classList.remove('limit-height'); limitBox.style.maxHeight = ''; var more = open.closest('.read-more'); if (more) more.remove(); }); } function initFlashQueryCleanup() { document.querySelectorAll('[data-aksrt-flash-query]').forEach(function (node) { var queryKey = node.getAttribute('data-aksrt-flash-query'); if (!queryKey || !window.history || typeof window.history.replaceState !== 'function') return; var url = new URL(window.location.href); if (!url.searchParams.has(queryKey)) return; url.searchParams.delete(queryKey); window.history.replaceState({}, '', url.toString()); }); } function init() { initPostToc(); initLightbox(); initContentExpand(); initFlashQueryCleanup(); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();