- rewrite schemas for posts, tab_posts, oneline_posts, hot_posts, term_cards, term_aggregation, media_cards, combo_info, partners, recent_comments, posts_toc and slider_media_combo to mirror the modern reference modules field by field (options, defaults, dependencies, min/max/step, subheadings) - port reference renderers: hot ranking with TOP badges, category aggregation card, graphic cover cards, partners CSS marquee, combo info cards with auto band palette, recent comment list - rename 分类与标签聚合卡片 to 分类聚合卡片 and restrict it to categories (no tags/topics branch in this project) - drop topics filter fields and the topics query branch; align orderby value domain with supported post meta - add searchable sortable terms admin field type and spinner unit suffix rendering - unify widget pagination and lazy loading on the REST client with the runtime-owned ias reveal trigger; remove the legacy post_ajax_trigger dual path - align section-navs TOC with the reference contract (wznav ids, 3-heading minimum, zib-widget box)
142 lines
4.2 KiB
JavaScript
142 lines
4.2 KiB
JavaScript
/**
|
||
* AKSRT Section Navs — legacy section_navs parity (posts-nav-lists + scrollspy).
|
||
*
|
||
* Builds TOC from [data-nav] h1–h4 into .posts-nav-box / .posts-nav-lists.
|
||
*
|
||
* @package AKSRT
|
||
*/
|
||
(function () {
|
||
'use strict';
|
||
|
||
var HEADING_SEL = 'h1, h2, h3, h4';
|
||
var MIN_HEADINGS = 3;
|
||
var NAVBOX = '.posts-nav-box';
|
||
var NAV_CLASS = 'posts-nav-lists';
|
||
|
||
function isExcluded(el) {
|
||
return el.classList.contains('item-heading') || !!el.closest('.no-nav');
|
||
}
|
||
|
||
function ensureId(el, index) {
|
||
if (!el.id) {
|
||
el.id = 'wznav_' + index;
|
||
}
|
||
return el.id;
|
||
}
|
||
|
||
function buildLists(root) {
|
||
var headings = root.querySelectorAll(HEADING_SEL);
|
||
var html = '';
|
||
var count = 0;
|
||
headings.forEach(function (h, i) {
|
||
if (isExcluded(h)) return;
|
||
var id = ensureId(h, i);
|
||
var tag = h.tagName.toUpperCase();
|
||
var text = (h.textContent || '').trim();
|
||
if (!text) return;
|
||
html += '<li class="n-' + tag + '"><a href="#' + id + '">' + text + '</a></li>';
|
||
count++;
|
||
});
|
||
return count >= MIN_HEADINGS ? html : '';
|
||
}
|
||
|
||
function fillBoxes(listsHtml) {
|
||
document.querySelectorAll(NAVBOX).forEach(function (box) {
|
||
var existing = box.querySelector('.' + NAV_CLASS);
|
||
if (existing) {
|
||
existing.innerHTML = listsHtml;
|
||
return;
|
||
}
|
||
var title = box.getAttribute('data-title') || '';
|
||
var titleHtml = title
|
||
? '<div class="box-body notop"><div class="title-theme">' + title + '</div></div>'
|
||
: '';
|
||
box.insertAdjacentHTML(
|
||
'beforeend',
|
||
titleHtml +
|
||
'<div class="zib-widget"><div class="' +
|
||
NAV_CLASS +
|
||
' scroll-y mini-scrollbar list-unstyled">' +
|
||
listsHtml +
|
||
'</div></div>'
|
||
);
|
||
});
|
||
}
|
||
|
||
function smoothTo(hash) {
|
||
var el = document.querySelector(hash);
|
||
if (!el) return;
|
||
var offset = 0;
|
||
var header = document.querySelector('.header');
|
||
if (document.body.classList.contains('nav-fixed') && header) {
|
||
offset = header.offsetHeight + 12;
|
||
}
|
||
var top = el.getBoundingClientRect().top + window.pageYOffset - offset;
|
||
window.scrollTo({ top: top, behavior: 'smooth' });
|
||
}
|
||
|
||
function bindClicks() {
|
||
document.addEventListener('click', function (e) {
|
||
var a = e.target && e.target.closest ? e.target.closest('.' + NAV_CLASS + ' a[href^="#"]') : null;
|
||
if (!a) return;
|
||
var href = a.getAttribute('href');
|
||
if (!href || href.length < 2) return;
|
||
e.preventDefault();
|
||
history.replaceState(null, '', href);
|
||
smoothTo(href);
|
||
});
|
||
}
|
||
|
||
function scrollspy() {
|
||
var links = document.querySelectorAll('.' + NAV_CLASS + ' a[href^="#"]');
|
||
if (!links.length) return;
|
||
var map = [];
|
||
links.forEach(function (a) {
|
||
var id = a.getAttribute('href').slice(1);
|
||
var el = document.getElementById(id);
|
||
if (el) map.push({ el: el, a: a, li: a.parentElement });
|
||
});
|
||
function update() {
|
||
var y = window.scrollY + 110;
|
||
var current = null;
|
||
for (var i = 0; i < map.length; i++) {
|
||
if (map[i].el.offsetTop <= y) current = map[i];
|
||
}
|
||
map.forEach(function (m) {
|
||
if (m.li) m.li.classList.toggle('active', m === current);
|
||
});
|
||
}
|
||
window.addEventListener('scroll', update, { passive: true });
|
||
update();
|
||
}
|
||
|
||
function autoHash() {
|
||
if (window.location.hash) {
|
||
setTimeout(function () {
|
||
smoothTo(window.location.hash);
|
||
}, 40);
|
||
}
|
||
}
|
||
|
||
function init() {
|
||
if (document.documentElement.dataset.aksrtSectionNavInitialized === '1') return;
|
||
document.documentElement.dataset.aksrtSectionNavInitialized = '1';
|
||
if (document.querySelector('.posts-nav-box .toc-list, .posts-nav-box.toc-widget .toc-list')) {
|
||
return;
|
||
}
|
||
var root = document.querySelector('[data-nav], .article-content, .entry-content, main.article');
|
||
if (!root) return;
|
||
var listsHtml = buildLists(root);
|
||
if (!listsHtml) return;
|
||
if (!document.querySelector(NAVBOX) && !document.querySelector('.' + NAV_CLASS)) {
|
||
return;
|
||
}
|
||
fillBoxes(listsHtml);
|
||
bindClicks();
|
||
scrollspy();
|
||
autoHash();
|
||
}
|
||
|
||
jQuery(document).off('auto_fun.aksrt-section-navs').on('auto_fun.aksrt-section-navs', init);
|
||
})();
|