Replace hybrid site-nav/drawer shell with zibll navbar-top layouts 1/2/3, body.mobile-navbar-show drawer, wired NavWalker + aksrt_menu_options meta, nav_folding/chevron, VIP switches, and SPA/PHP schema parity. No dual-class compat paths.
169 lines
5.4 KiB
JavaScript
169 lines
5.4 KiB
JavaScript
/**
|
|
* AKSRT Scroll Behaviors — back-to-top, floating buttons, reading progress, nav scroll
|
|
*/
|
|
(function () {
|
|
"use strict";
|
|
|
|
function initBackToTop() {
|
|
var el = document.getElementById("float-back-to-top") || document.getElementById("back-to-top");
|
|
if (!el) return;
|
|
|
|
function onScroll() {
|
|
if (window.scrollY > 400) {
|
|
el.classList.add("is-visible");
|
|
} else {
|
|
el.classList.remove("is-visible");
|
|
}
|
|
}
|
|
|
|
window.addEventListener("scroll", onScroll, { passive: true });
|
|
onScroll();
|
|
|
|
el.addEventListener("click", function (e) {
|
|
e.preventDefault();
|
|
if (window.aksrt && aksrt.scrollTopTo) {
|
|
aksrt.scrollTopTo(0);
|
|
} else {
|
|
window.scrollTo({ top: 0, behavior: "smooth" });
|
|
}
|
|
});
|
|
}
|
|
|
|
function initFloatingButtons() {
|
|
var wrap = document.getElementById("float-right-btns");
|
|
if (!wrap) return;
|
|
|
|
function debugEnabled() {
|
|
return !!(window.aksrtData && aksrtData.debug);
|
|
}
|
|
|
|
function debugLog(message, context, level) {
|
|
if (!debugEnabled()) return;
|
|
var method = level === "error" ? "error" : (level === "warn" ? "warn" : "log");
|
|
console[method]("[AKSRT FloatingButtons] " + message, context || {});
|
|
}
|
|
|
|
function reportDebug(eventName, payload) {
|
|
if (!(window.aksrtData && aksrtData.debugLog && aksrtData.ajaxUrl && aksrtData.nonce)) {
|
|
return;
|
|
}
|
|
|
|
var body = new URLSearchParams();
|
|
body.set("action", "aksrt_frontend_debug");
|
|
body.set("nonce", aksrtData.nonce);
|
|
body.set("source", "floating_buttons");
|
|
body.set("event", eventName);
|
|
body.set("page", window.location.href);
|
|
if (payload && payload.text) body.set("text", String(payload.text));
|
|
if (payload && payload.size) body.set("size", String(payload.size));
|
|
if (payload && payload.error) body.set("error", String(payload.error));
|
|
|
|
fetch(aksrtData.ajaxUrl, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" },
|
|
credentials: "same-origin",
|
|
body: body.toString()
|
|
}).catch(function () {});
|
|
}
|
|
|
|
var scrollTimer = null;
|
|
|
|
function setHidden(hidden) {
|
|
wrap.classList.toggle("is-hidden", !!hidden);
|
|
}
|
|
|
|
function syncFromScrollBus() {
|
|
var body = document.body;
|
|
if (wrap.classList.contains("scroll-down-hide")) {
|
|
setHidden(body.classList.contains("scroll-down"));
|
|
}
|
|
if (wrap.classList.contains("scrolling-hide")) {
|
|
setHidden(true);
|
|
window.clearTimeout(scrollTimer);
|
|
scrollTimer = window.setTimeout(function () {
|
|
if (!body.classList.contains("scroll-down")) setHidden(false);
|
|
}, 160);
|
|
}
|
|
}
|
|
|
|
window.addEventListener("scroll", function () {
|
|
requestAnimationFrame(syncFromScrollBus);
|
|
}, { passive: true });
|
|
|
|
wrap.addEventListener("click", function (event) {
|
|
var btn = event.target.closest(".float-btn");
|
|
if (!btn) return;
|
|
|
|
if (btn.getAttribute("href") === "#") {
|
|
event.preventDefault();
|
|
}
|
|
|
|
if (btn.hasAttribute("data-action") && btn.getAttribute("data-action") === "toggle-theme") {
|
|
event.preventDefault();
|
|
if (window.aksrt && typeof aksrt.toggleTheme === "function") {
|
|
aksrt.toggleTheme();
|
|
} else {
|
|
document.documentElement.classList.toggle("dark");
|
|
document.body.classList.toggle("dark-theme");
|
|
}
|
|
}
|
|
|
|
btn.classList.remove("is-rippling");
|
|
window.requestAnimationFrame(function () {
|
|
btn.classList.add("is-rippling");
|
|
window.setTimeout(function () {
|
|
btn.classList.remove("is-rippling");
|
|
}, 600);
|
|
});
|
|
});
|
|
}
|
|
|
|
function initReadingProgress() {
|
|
var bar = document.getElementById("reading-progress-global");
|
|
if (!bar) return;
|
|
|
|
function update() {
|
|
var doc = document.documentElement;
|
|
var scrollable = doc.scrollHeight - window.innerHeight;
|
|
var pct = scrollable <= 0 ? 100 : Math.min(100, Math.max(0, (window.scrollY / scrollable) * 100));
|
|
bar.style.width = pct + "%";
|
|
bar.setAttribute("aria-valuenow", String(Math.round(pct)));
|
|
}
|
|
|
|
window.addEventListener("scroll", update, { passive: true });
|
|
window.addEventListener("resize", update, { passive: true });
|
|
update();
|
|
}
|
|
|
|
function initNavScrollState() {
|
|
// Zibll: hide is CSS on body.scroll-down + header.scroll-down-hide.
|
|
// Keep is-scrolled on .header for optional consumers.
|
|
var header = document.querySelector(".header");
|
|
var ticking = false;
|
|
|
|
function update() {
|
|
ticking = false;
|
|
var body = document.body;
|
|
if (header) {
|
|
header.classList.toggle("is-scrolled", body.classList.contains("body-scroll"));
|
|
}
|
|
}
|
|
|
|
function onScroll() {
|
|
if (!ticking) {
|
|
window.requestAnimationFrame(update);
|
|
ticking = true;
|
|
}
|
|
}
|
|
|
|
window.addEventListener("scroll", onScroll, { passive: true });
|
|
window.addEventListener("resize", onScroll, { passive: true });
|
|
update();
|
|
}
|
|
|
|
window.AksrtFrontend.register("aksrt-floating-buttons", function () { initFloatingButtons(); });
|
|
window.AksrtFrontend.register("aksrt-back-to-top", function () { initBackToTop(); });
|
|
window.AksrtFrontend.register("aksrt-reading-progress", function () { initReadingProgress(); });
|
|
window.AksrtFrontend.register("aksrt-nav-scroll-state", function () { initNavScrollState(); });
|
|
})();
|