fix(runtime): 按参考主题硬切换为 loader/main/auto_fun 单一 DOM 生命周期

- 删除 AksrtFrontend registry/rehydrate 双路架构及 build/public.js 拼包入口,
  前台唯一初始路径为 PHP 本地栈(jQuery 1.9.1 → Bootstrap 3.4.1)
  → loader_js(_win/aksrtData 唯一注入)→ tbquire(['main']) → runtime/main.min.js
- window.auto_fun = debounce(z_auto_fun, 100) 为唯一重扫入口;所有模块改为
  执行一次 + off/on('auto_fun.aksrt-*') 命名空间重扫,data/class 标记幂等
- 局部更新协议统一:HTML 注入 → post_ajax.ed → auto_fun();
  远程 modal → loaded.bs.modal → auto_fun();JSON 成功 → zib_ajax.success
- 灯箱恢复 Miniimgbox/imgbox 唯一 owner(imgbox-container、a[data-imgbox]、
  imgbox_data),删除 AksrtLightbox/data-aksrt-lightbox 第二实现及 CSS/overlay,
  _win.imgbox* 重新接上 post-display 设置
- 死代码清理:runtime 下 11 组被自有实现替代的旧模块副本、无消费 vendored 库、
  顶层 grade.min.js、revenue.js、无调用方的 aksrt_get_win_runtime_config(),
  以及 loader 中 16 条死 mapping
- PHP 入队改为本地栈 + loader_js,routed/widget/submit 依赖统一换绑;
  用户卡片发布按钮恢复 nav_user_newposts_btn 设置门控
- 测试对齐:新增 frontend-lifecycle-contract,重写 navigation/lazyload/toast/
  auth-source/comment/page-display/post-visual 等断言为目标架构契约

验证:node --test widget-system+navigation 223 通过 0 失败;
构建脚本重建 main/imgbox min 与 CSS bundles;改动 PHP php -l、JS node --check
全部通过;git diff --check 干净;credits 重入 harness 通过。
This commit is contained in:
kate522 committed 2026-09-03 12:44:31 +08:00
1 parent 1cd81fb61a
commit 5fd7c212ed
124 files changed
+2128 -17328

No files matched your search

+2
View File
@@ -333,6 +333,8 @@
url: href,
payload: payload,
});
// legacy 契约:post_ajax.ed 之后调用全局 auto_fun 重扫新内容。
if (typeof window.auto_fun === "function") window.auto_fun();
document.dispatchEvent(
new CustomEvent("aksrt:posts:rendered", {
bubbles: true,
+20 -7
View File
@@ -7,7 +7,8 @@
function initArchiveFilter(root) {
var scope = root || document;
var bar = scope.querySelector(".archive-filter-bar--ajax[data-ajax-archive]");
if (!bar) return;
if (!bar || bar.dataset.aksrtArchiveInit === "1") return;
bar.dataset.aksrtArchiveInit = "1";
var archiveType = bar.dataset.ajaxArchive || "category";
var termId = parseInt(bar.dataset.termId, 10) || 0;
@@ -95,11 +96,13 @@
var temp = document.createElement("div");
temp.innerHTML = data.html;
while (temp.firstChild) wrap.appendChild(temp.firstChild);
} else {
rebuildEmptyState();
} else {
rebuildEmptyState();
}
// legacy 事件顺序:先 post_ajax.ed,再全局 auto_fun 重扫
wrap.dispatchEvent(new CustomEvent("post_ajax.ed", { bubbles: true }));
if (typeof window.auto_fun === "function") window.auto_fun();
}
if (window.AksrtFrontend) AksrtFrontend.rehydrate(wrap, "ajax");
}
if (pushState !== false) {
var url = new URL(window.location.href);
url.searchParams.delete("orderby");
@@ -177,7 +180,17 @@
});
}
window.AksrtFrontend.register("aksrt-archive-filter", function (root) {
function init(root) {
initArchiveFilter(root);
});
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", function () { init(); });
} else {
init();
}
// AJAX 注入新内容后由 auto_fun 重扫(bar 级 data 标记保证幂等)。
if (window.jQuery) {
window.jQuery(document).on("auto_fun", function () { init(); });
}
})();
+21 -6
View File
@@ -23,7 +23,8 @@
var btn = document.getElementById("search-clear-btn");
var input = document.getElementById("search-page-input");
if (btn && input) {
if (btn && input && !btn.dataset.aksrtSearchClearBound) {
btn.dataset.aksrtSearchClearBound = "1";
var syncClearButton = function () {
var hasValue = input.value.trim().length > 0;
btn.classList.toggle("is-visible", hasValue);
@@ -63,6 +64,8 @@
if (!buttons.length) return;
buttons.forEach(function (button) {
if (button.dataset.aksrtArticleToolBound) return;
button.dataset.aksrtArticleToolBound = "1";
button.addEventListener("click", function () {
var tool = button.getAttribute("data-article-tool");
if (tool === "print") {
@@ -327,9 +330,21 @@
}
}
window.AksrtFrontend.register("aksrt-search-clear", function () { initSearchClear(); });
window.AksrtFrontend.register("aksrt-article-tools", function () { initArticleTools(); });
window.AksrtFrontend.register("aksrt-post-meta-menus", function (root) { initPostMetaMenus(root); });
window.AksrtFrontend.register("aksrt-password-toggles", function (root) { initPasswordToggles(root); });
window.AksrtFrontend.register("aksrt-interaction-bar", function (root) { initInteractionBar(root); });
function init(root) {
initSearchClear();
initArticleTools();
initPostMetaMenus(root);
initPasswordToggles(root);
initInteractionBar(root);
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", function () { init(); });
} else {
init();
}
// AJAX 注入新内容后由 auto_fun 重扫(各 init 均带 data 标记,重复调用幂等)。
if (window.jQuery) {
window.jQuery(document).off("auto_fun.aksrt-article").on("auto_fun.aksrt-article", function () { init(); });
}
})();
+25 -40
View File
@@ -4,10 +4,6 @@
(function () {
'use strict';
function $(sel, root) {
return (root || document).querySelector(sel);
}
function FixedInput(el, action) {
if (!el) return;
if (!el.dataset.fixedBound) {
@@ -39,6 +35,19 @@
}
}
document.addEventListener('click', function (e) {
var trigger = e.target && e.target.closest ? e.target.closest('[fixed-input]') : null;
if (!trigger) return;
e.preventDefault();
var targetSel = trigger.getAttribute('fixed-input') || '#respond';
var panel = document.querySelector(targetSel);
var comments = document.getElementById('comments');
if (comments && comments.scrollIntoView) {
comments.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
FixedInput(panel, 'show');
});
// Autoheight textareas.
function bindAutoheight(ta) {
if (!ta || ta.dataset.autoheightBound) return;
@@ -54,49 +63,25 @@
resize();
}
function scopeFor(root) {
return root && root.querySelectorAll ? root : document;
function scan() {
document.querySelectorAll('textarea[autoheight], textarea.grin').forEach(bindAutoheight);
}
function scan(root) {
var scope = scopeFor(root);
if (scope.nodeType === 1 && scope.matches('textarea[autoheight], textarea.grin')) {
bindAutoheight(scope);
}
scope.querySelectorAll('textarea[autoheight], textarea.grin').forEach(bindAutoheight);
}
var globalsBound = false;
function bindGlobals() {
if (globalsBound) return;
globalsBound = true;
document.addEventListener('click', function (e) {
var trigger = e.target && e.target.closest ? e.target.closest('[fixed-input]') : null;
if (!trigger) return;
e.preventDefault();
var targetSel = trigger.getAttribute('fixed-input') || '#respond';
var panel = document.querySelector(targetSel);
var comments = document.getElementById('comments');
if (comments && comments.scrollIntoView) {
comments.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
FixedInput(panel, 'show');
});
}
window.AksrtFrontend.register('aksrt-comment-fixed-input', function (root, reason) {
bindGlobals();
scan(root);
root = root || document;
var respond = root.nodeType === 1 && root.matches && root.matches('#respond')
? root
: (root.querySelector ? root.querySelector('#respond') : document.getElementById('respond'));
function init() {
scan();
// Expose for submit hide.
var respond = document.getElementById('respond');
if (respond) {
respond.aksrtFixedInput = function (action) {
FixedInput(respond, action);
};
}
});
}
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
else init();
// AJAX 注入新内容后由 auto_fun 重扫(dataset 标记保证幂等)。
if (window.jQuery) window.jQuery(document).on('auto_fun', init);
window.AksrtFixedInput = FixedInput;
})();
+28 -10
View File
@@ -6,7 +6,8 @@
function initCommentSystem() {
var form = document.querySelector("#commentform");
if (!form) return;
if (!form || form.dataset.aksrtCommentInit === "1") return;
form.dataset.aksrtCommentInit = "1";
// 修复:同时匹配 button 和 input 元素
var submitBtn = form.querySelector('[type="submit"]');
@@ -338,7 +339,9 @@
notyf('评论发布成功', 'success');
}
if (window.AksrtFrontend) AksrtFrontend.rehydrate(newComment, 'ajax');
// legacy 事件顺序:先 post_ajax.ed,再全局 auto_fun 重扫
newComment.dispatchEvent(new CustomEvent('post_ajax.ed', { bubbles: true }));
if (typeof window.auto_fun === 'function') window.auto_fun();
updateCommentCount(1);
}
@@ -523,7 +526,9 @@
var currentCount = commentsArea.querySelector(".title-theme small");
if (currentCount && data.count_text) currentCount.textContent = data.count_text;
if (window.AksrtFrontend) AksrtFrontend.rehydrate(commentsArea, "ajax");
// legacy 事件顺序:先 post_ajax.ed,再全局 auto_fun 重扫
newListWrap.dispatchEvent(new CustomEvent("post_ajax.ed", { bubbles: true }));
if (typeof window.auto_fun === "function") window.auto_fun();
}
function fetchCommentFragment(opts) {
@@ -575,7 +580,7 @@
/* ====== 评论排序(最新 / 最早) ====== */
/**
* Locate #id within a rehydrate root.
* Locate #id within the given scope.
* Document has getElementById; Element roots (AJAX panels) only have querySelector.
*/
function findInScope(scope, id) {
@@ -596,9 +601,8 @@
function initCommentOrder(root) {
var scope = root || document;
var commentsArea = findInScope(scope, "comments");
if (!commentsArea) return;
// Event delegation survives filter HTML replacement after AJAX rehydrate.
if (commentsArea.dataset.orderInit === "1") return;
if (!commentsArea || commentsArea.dataset.orderInit === "1") return;
// Event delegation survives filter HTML replacement after AJAX refresh.
commentsArea.dataset.orderInit = "1";
function renderLoadingState() {
@@ -683,6 +687,8 @@
/* ====== 数字分页跳页(legacy pag-jump) ====== */
var commentPageJumpBound = false;
function jumpToCommentPage(page) {
loadCommentPage(page).catch(function (error) {
console.error("[AKSRT Comment] 跳页失败:", error);
@@ -691,6 +697,8 @@
}
function initCommentPageJump() {
if (commentPageJumpBound) return;
commentPageJumpBound = true;
document.addEventListener("click", function (e) {
var jump = e.target.closest ? e.target.closest("#comments .pag-jump") : null;
if (!jump) return;
@@ -708,12 +716,22 @@
});
}
window.AksrtFrontend.register("aksrt-comment-system", function () {
function init() {
stripCommentUrlParams();
initCommentSystem();
initCommentPageJump();
});
window.AksrtFrontend.register("aksrt-comment-order", function (root) { initCommentOrder(root); });
initCommentOrder();
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init);
} else {
init();
}
// AJAX 注入新内容后由 auto_fun 重扫(form/commentsArea 均带 data 标记,重复调用幂等)。
if (window.jQuery) {
window.jQuery(document).on("auto_fun", init);
}
// 供 pagination.js 等模块复用:评论页码加载 / 列表刷新(局部 DOM,无 ? 参数)。
window.AksrtComments = {
+8 -3
View File
@@ -6,14 +6,15 @@
function initFooterTabbar() {
var tabbar = document.getElementById("footer-tabbar");
if (!tabbar) return;
if (!tabbar || tabbar.dataset.aksrtTabbarInit === "1") return;
tabbar.dataset.aksrtTabbarInit = "1";
var addBackdrop = document.getElementById("tabbar-add-backdrop");
var ticking = false;
var scrollThreshold = 100;
var isHidden = false;
// Use body scroll bus classes from aksrt-runtime.js
// Use body scroll bus classes from runtime/main.js
function handleScrollDownHide() {
var body = document.body;
var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
@@ -136,5 +137,9 @@
});
}
window.AksrtFrontend.register("aksrt-footer-tabbar", function () { initFooterTabbar(); });
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initFooterTabbar);
} else {
initFooterTabbar();
}
})();
+69 -48
View File
@@ -4,18 +4,6 @@
(function () {
"use strict";
var globalsBound = false;
function scopeFor(root) {
return root && root.querySelectorAll ? root : document;
}
function eachMatch(root, selector, callback) {
var scope = scopeFor(root);
if (scope.nodeType === 1 && scope.matches(selector)) callback(scope);
scope.querySelectorAll(selector).forEach(callback);
}
function renderGradientBackground(container) {
if (!container || container.dataset.aksrtGradientState || typeof window.Grade !== "function") return;
@@ -44,15 +32,26 @@
}
function initGradientBackgrounds(root) {
eachMatch(root, ".gradient-bg", renderGradientBackground);
var scope = root || document;
if (scope.nodeType === 1 && scope.matches(".gradient-bg")) {
renderGradientBackground(scope);
}
scope.querySelectorAll(".gradient-bg").forEach(renderGradientBackground);
}
document.addEventListener("lazyloaded", function (event) {
if (!(event.target instanceof Element) || !event.target.matches(".gradient-bg img")) return;
renderGradientBackground(event.target.closest(".gradient-bg"));
}, true);
function initPostThumbMedia(root) {
eachMatch(root, "[data-post-thumb-video]", function (box) {
var scope = root || document;
scope.querySelectorAll("[data-post-thumb-video]").forEach(function (box) {
if (box.dataset.aksrtThumbVideoBound === "1") return;
box.dataset.aksrtThumbVideoBound = "1";
var video = box.querySelector("video");
if (!video) return;
box.dataset.aksrtThumbVideoBound = "1";
function loadVideo() {
if (!video.getAttribute("src") && video.dataset.src) {
@@ -83,17 +82,35 @@
});
}
function initSlideCovers(root) {
eachMatch(root, ".single-cover--slide", function (cover) {
if (cover.dataset.aksrtSlideCoverBound === "1") return;
function init(root) {
initPostThumbMedia(root);
initGradientBackgrounds(root);
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", function () { init(); });
} else {
init();
}
// AJAX 注入新内容后由 auto_fun 重扫(各 init 均带 data 标记,重复调用幂等)。
if (window.jQuery) {
window.jQuery(document).on("auto_fun", function () { init(); });
}
})();
(function () {
"use strict";
function initSlideCovers() {
var covers = document.querySelectorAll(".single-cover--slide");
covers.forEach(function (cover) {
var slides = cover.querySelectorAll(".single-cover__slide");
var dots = cover.querySelectorAll(".single-cover__dot");
if (slides.length < 2) return;
cover.dataset.aksrtSlideCoverBound = "1";
var current = 0;
var interval = 5000;
var timer = null;
function goTo(idx) {
slides[current].classList.remove("is-active");
@@ -103,32 +120,33 @@
if (dots[current]) dots[current].classList.add("is-active");
}
function startTimer() {
timer = window.setInterval(function () {
goTo((current + 1) % slides.length);
}, interval);
}
var timer = setInterval(function () {
goTo((current + 1) % slides.length);
}, interval);
startTimer();
dots.forEach(function (dot, i) {
dot.addEventListener("click", function () {
window.clearInterval(timer);
clearInterval(timer);
goTo(i);
startTimer();
timer = setInterval(function () {
goTo((current + 1) % slides.length);
}, interval);
});
});
});
}
function bindGlobals() {
if (globalsBound) return;
globalsBound = true;
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initSlideCovers);
} else {
initSlideCovers();
}
})();
document.addEventListener("lazyloaded", function (event) {
if (!(event.target instanceof Element) || !event.target.matches(".gradient-bg img")) return;
renderGradientBackground(event.target.closest(".gradient-bg"));
}, true);
(function () {
"use strict";
function initHiddenContent() {
document.addEventListener("click", function (e) {
var btn = e.target.closest(".aksrt-hidden-content__submit-btn");
if (!btn) return;
@@ -149,7 +167,7 @@
var formData = new FormData();
formData.append("action", "aksrt_check_visibility");
formData.append("_nonce", (window.aksrtData && window.aksrtData.visibilityNonce) || "");
formData.append("_nonce", (window.aksrtData && aksrtData.visibilityNonce) || "");
formData.append("mode", mode);
formData.append("pid", pid);
if (password) formData.append("password", password);
@@ -157,7 +175,7 @@
btn.disabled = true;
btn.textContent = "...";
fetch((window.aksrtData && window.aksrtData.ajaxUrl) || "/wp-admin/admin-ajax.php", {
fetch((window.aksrtData && aksrtData.ajaxUrl) || "/wp-admin/admin-ajax.php", {
method: "POST",
body: formData,
credentials: "same-origin",
@@ -180,19 +198,22 @@
});
});
// Handle Enter key on password input
document.addEventListener("keydown", function (e) {
if (e.key !== "Enter" || !e.target.classList.contains("aksrt-hidden-content__password-input")) return;
e.preventDefault();
var wrapper = e.target.closest(".aksrt-hidden-content--locked");
var btn = wrapper ? wrapper.querySelector(".aksrt-hidden-content__submit-btn") : null;
if (btn) btn.click();
if (e.key === "Enter" && e.target.classList.contains("aksrt-hidden-content__password-input")) {
e.preventDefault();
var wrapper = e.target.closest(".aksrt-hidden-content--locked");
if (wrapper) {
var btn = wrapper.querySelector(".aksrt-hidden-content__submit-btn");
if (btn) btn.click();
}
}
});
}
window.AksrtFrontend.register("aksrt-misc", function (root, reason) {
bindGlobals();
initPostThumbMedia(root);
initGradientBackgrounds(root);
initSlideCovers(root);
});
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initHiddenContent);
} else {
initHiddenContent();
}
})();
+21 -8
View File
@@ -3,7 +3,7 @@
*
* Owns the modal shell while adding cancellable loaders,
* short in-memory caching, request deduplication, retryable errors, focus
* restoration, and modal-scoped rehydration.
* restoration, and legacy `loaded.bs.modal` content lifecycle (auto_fun rescan).
*
* @package AKSRT
*/
@@ -184,7 +184,7 @@
}));
if (options.html !== undefined) {
rehydrate(session);
notifyContentLoaded(session);
telemetryMark(session, "first-content");
telemetryMark(session, "ready");
if (typeof options.onContent === "function") options.onContent(options.html, session);
@@ -193,9 +193,11 @@
return session;
}
function rehydrate(session) {
if (!session || !session.content) return;
window.AksrtFrontend.rehydrate(session.content, "modal");
// legacy 契约:modal 内容注入后触发 loaded.bs.modal,
// 由全局委托(见文件底部)驱动 auto_fun 重扫,不做模块内扫描。
function notifyContentLoaded(session) {
if (!session || !session.shell || !window.jQuery) return;
window.jQuery(session.shell).trigger("loaded.bs.modal");
}
function abortSessionRequest(session) {
@@ -260,7 +262,7 @@
'</div><div class="but-average modal-buts">' +
'<button type="button" class="but" data-aksrt-modal-retry>重试</button>' +
'<button type="button" class="but" data-aksrt-modal-close>关闭</button></div>';
rehydrate(session);
notifyContentLoaded(session);
if (typeof session.options.onError === "function") session.options.onError(error, session);
}
@@ -281,7 +283,7 @@
}
setState(session, "ready");
telemetryMark(session, "first-content");
rehydrate(session);
notifyContentLoaded(session);
telemetryMark(session, "ready");
if (typeof session.options.onData === "function") session.options.onData(data, session, result);
return;
@@ -298,7 +300,7 @@
session.content.innerHTML = html;
setState(session, "ready");
telemetryMark(session, "first-content");
rehydrate(session);
notifyContentLoaded(session);
telemetryMark(session, "ready");
if (typeof session.options.onContent === "function") session.options.onContent(html, session);
}
@@ -422,4 +424,15 @@
};
document.dispatchEvent(new CustomEvent("aksrt:modal-runtime:ready"));
// legacy 契约(只绑定一次):modal 展示/内容注入后调用全局 auto_fun 重扫。
if (window.jQuery) {
window.jQuery(document).on(
"loaded.bs.modal show.bs.modal",
".modal, .aksrt-modal-runtime",
function () {
if (typeof window.auto_fun === "function") window.auto_fun();
}
);
}
})(window, document);
+16 -4
View File
@@ -173,9 +173,9 @@
target.appendChild(newItems[0]);
}
}
if (window.AksrtFrontend) {
AksrtFrontend.rehydrate(target, "ajax");
}
// legacy 事件顺序:先 post_ajax.ed,再全局 auto_fun 重扫
target.dispatchEvent(new CustomEvent("post_ajax.ed", { bubbles: true }));
if (typeof window.auto_fun === "function") window.auto_fun();
nextPage++;
container.dataset.nextPage = String(nextPage);
if (fromAuto) {
@@ -284,5 +284,17 @@
});
}
window.AksrtFrontend.register("aksrt-ajax-pagination", function (root) { initAjaxPagination(root); });
function init(root) {
initAjaxPagination(root);
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", function () { init(); });
} else {
init();
}
// AJAX 注入新内容后由 auto_fun 重扫(container 级 data 标记保证幂等)。
if (window.jQuery) {
window.jQuery(document).on("auto_fun", function () { init(); });
}
})();
+10 -1
View File
@@ -182,7 +182,12 @@
if (ddBtn) ddBtn.setAttribute("aria-pressed", isDark ? "true" : "false");
}
var themeInitialized = false;
function initTheme() {
if (themeInitialized) return;
themeInitialized = true;
var stored = getStoredTheme();
var configuredMode = (window.aksrtData && aksrtData.themeMode) || "light";
if (stored === "dark" || stored === "light") {
@@ -265,5 +270,9 @@
};
}
window.AksrtFrontend.register("aksrt-theme", function () { initTheme(); });
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initTheme);
} else {
initTheme();
}
})();