feat(runtime): 全站前端脚本统一接入 AksrtFrontend 全局 DOM 生命周期

- rehydrate.js 新增 boot()/aksrt:ready 事件,支持 boot 后晚注册立即以 init 触发
- aksrt-runtime.js 初始加载改走 AksrtFrontend.boot,tooltip/倒计时注册为组件
- 约 30 个前端脚本(首页、评论、支付、路由、页面叶子、widgets)
  从直接 DOMContentLoaded 迁移为 AksrtFrontend.register,并加幂等标记
- section-navs 依赖改为 aksrt-runtime,保证注册时序
- 清理死代码:删除孤儿 loader.js/main.js 及 runtime/page-navs 遗留副本
- loader.js 移除已迁移模块的 tbquire 路径映射,main.js 相应瘦身
- build-public-assets.mjs 增加 runtime/main.min.js 自动压缩步骤
- 新增 4 个契约测试(homepage-dom/rehydrate-runtime/global-dom-init/
  public-bundle-parity),3 个既有 harness 适配注册表初始化方式
This commit is contained in:
2026-09-02 21:48:56 +08:00
parent 5984d4e42d
commit 1f4a39d8f8
60 changed files with 1810 additions and 1742 deletions
+19 -67
View File
@@ -269,64 +269,7 @@
});
}, true);
// ══════════════════════════════════════════════════════════════
// §10.10a — 拦截 vendor 评论脚本 & 解绑 vendor ajax 委托
// ══════════════════════════════════════════════════════════════
// vendor 链路:loader.js(tbquire,改造版 RequireJS)→ main.min.js 检测到
// #commentform/#postcomments 即 tbquire(["comment"]) 懒加载 comment.min.js;
// 检测到 .dropdown-code/.dropdown-image 即 tbquire(["input-expand"])。
// AKSRT 自有评论脚本(comments/comment-tools/comment-fixed-input/
// comment-move-form/comment-ajax)已承担全部行为,vendor comment.min.js 的
// 7 条 body 委托会双路触发(提交 legacy action=submit_comment 无处理器,
// 即控制台「ajax请求错误」400 "0" 的来源;回复/排序/分页同理);
// vendor input-expand.min.js(表情/快捷回复旧链路,源文件已删除)同理不再下载。
//
// 双层防御:
// 1) tbfine 预注册空 'comment'/'input-expand' 模块 → tbquire 不再下载;
// 2) 若模块抢在注册前加载,退化为对 7 条委托做幂等 .off。
function stubVendorCommentModule() {
if (!(window.tbfine && window.tbquire && window.tbquire.defined)) return false;
try {
['comment', 'input-expand'].forEach(function (name) {
if (!window.tbquire.defined(name)) {
window.tbfine(name, [], function () { return {}; });
}
});
return true;
} catch (e) {
return false;
}
}
// main.min.js 的 body 级 legacy 委托同理摘除(vendor 只保留 UI 行为)。
function unbindVendorAjaxDelegates() {
stubVendorCommentModule();
if (!window.jQuery) return;
try {
var $body = jQuery('body');
$body.off('click', '[data-action]');
$body.off('click', '[ajax-action]');
$body.off('click', '.wp-ajax-submit,[zibajax="submit"]');
$body.off('click', '.initiate-checkin');
$body.off('click', '.oauth-untying');
// comment.min.js 的 7 条委托(legacy/js/comment.js 原始选择器)
$body.off('click', '[fixed-input]');
$body.off('click', '.commentlist .pagenav a,.comment-orderby');
$body.off('click', '.comment-edit-link,.comment-reply-link');
$body.off('keydown', '#comment');
$body.off('click', '.comment-trash-link');
$body.off('click', '.comment-approve-link');
$body.off('click', '#commentform #submit');
} catch (e) { /* vendor 运行时未就绪时忽略 */ }
}
var unbindVendorAjaxLoop = function () {
unbindVendorAjaxDelegates();
if (++unbindVendorAjaxLoop.tries >= 50) return; // ~10s @200ms 覆盖异步加载窗口
setTimeout(unbindVendorAjaxLoop, 200);
};
unbindVendorAjaxLoop.tries = 0;
unbindVendorAjaxLoop();
// Vendor modules are no longer dynamically loaded by the canonical frontend path.
// ══════════════════════════════════════════════════════════════
// §10.11 — [data-action] / [ajax-action] universal buttons
// ══════════════════════════════════════════════════════════════
@@ -533,13 +476,7 @@
// §10.11 — auto_fun: extended rehydration coverage
// ══════════════════════════════════════════════════════════════
aksrt.autoFun = function (root) {
root = root || document;
if (window.AksrtFrontend) {
AksrtFrontend.rehydrate(root, 'ajax');
}
// Tooltips
function initTooltips(root) {
root.querySelectorAll('[data-tooltip]').forEach(function (el) {
if (el.dataset.tooltipBound) return;
el.dataset.tooltipBound = '1';
@@ -557,8 +494,9 @@
if (el._aksrtTooltip) { el._aksrtTooltip.remove(); el._aksrtTooltip = null; }
});
});
}
// Countdowns
function initCountdowns(root) {
root.querySelectorAll('[data-countdown]').forEach(function (el) {
if (el.dataset.countdownBound) return;
el.dataset.countdownBound = '1';
@@ -572,6 +510,20 @@
el.textContent = (m < 10 ? '0' : '') + m + ':' + (s < 10 ? '0' : '') + s;
}, 1000);
});
}
AksrtFrontend.register('aksrt-tooltips', initTooltips);
AksrtFrontend.register('aksrt-countdowns', initCountdowns);
aksrt.autoFun = function (root, reason) {
root = root || document;
reason = reason || 'ajax';
if (!window.AksrtFrontend) return;
if (reason === 'init' && typeof AksrtFrontend.boot === 'function') {
AksrtFrontend.boot(root);
} else {
AksrtFrontend.rehydrate(root, reason);
}
};
// ══════════════════════════════════════════════════════════════
@@ -590,7 +542,7 @@
// ── DOMContentLoaded ──
function initRuntime() {
aksrt.autoFun(document);
aksrt.autoFun(document, 'init');
}
if (document.readyState === 'loading') {
+42 -16
View File
@@ -8,6 +8,8 @@
var modal = null;
var lastModalTrigger = null;
var qrStates = [];
var globalEventsBound = false;
var oauthResultChecked = false;
var oauthErrorMessages = {
access_denied: '已取消第三方授权',
cancelled: '已取消第三方授权',
@@ -507,6 +509,17 @@
}
function initRoot(root) {
root = root || document;
if (root.nodeType === 1 && root.matches('[data-aksrt-auth]')) {
initAuthRoot(root);
return;
}
if (root.querySelectorAll) root.querySelectorAll('[data-aksrt-auth]').forEach(initAuthRoot);
}
function initAuthRoot(root) {
if (root.dataset.aksrtAuthInitialized === '1') return;
root.dataset.aksrtAuthInitialized = '1';
root.querySelectorAll('input').forEach(function (input) {
if (!input.hasAttribute('placeholder')) input.setAttribute('placeholder', ' ');
});
@@ -662,10 +675,14 @@
}
}
function init() {
showOAuthResultToast();
document.querySelectorAll('[data-aksrt-auth]').forEach(initRoot);
function initGlobal() {
modal = document.querySelector('[data-auth-modal]');
if (!oauthResultChecked) {
oauthResultChecked = true;
showOAuthResultToast();
}
if (globalEventsBound) return;
globalEventsBound = true;
document.addEventListener('click', function (event) {
var trigger = event.target.closest('[data-aksrt-auth-required], .aksrt-login-trigger, #nav-login-btn, .signin-loader, .signup-loader, .qrcode-signin');
if (!trigger) return;
@@ -673,17 +690,7 @@
var tab = trigger.classList.contains('signup-loader') ? 'signup' : (trigger.classList.contains('qrcode-signin') ? 'oauth' : 'signin');
openModal(tab, trigger.dataset.authRedirect || window.location.href, trigger);
});
if (modal) {
modal.addEventListener('click', function (event) {
if (event.target.closest('[data-auth-close]')) closeModal(true);
});
document.addEventListener('keydown', handleModalKeydown);
if (modal.dataset.auto === '1' && Number(window.localStorage.getItem('aksrtAuthAutoUntil') || 0) < Date.now()) {
window.setTimeout(function () {
openModal(modal.querySelector('[data-aksrt-auth]').dataset.initialTab || 'signin', window.location.href, null);
}, Math.max(1, Number(modal.dataset.autoWait) || 5) * 1000);
}
}
document.addEventListener('keydown', handleModalKeydown);
document.addEventListener('visibilitychange', function () {
qrStates.forEach(function (state) {
if (document.visibilityState !== 'visible') stopQr(state.root);
@@ -692,6 +699,25 @@
});
}
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
else init();
function initModal() {
if (!modal || modal.dataset.aksrtAuthModalInitialized === '1') return;
modal.dataset.aksrtAuthModalInitialized = '1';
modal.addEventListener('click', function (event) {
if (event.target.closest('[data-auth-close]')) closeModal(true);
});
if (modal.dataset.auto === '1' && Number(window.localStorage.getItem('aksrtAuthAutoUntil') || 0) < Date.now()) {
window.setTimeout(function () {
var root = modal.querySelector('[data-aksrt-auth]');
if (root) openModal(root.dataset.initialTab || 'signin', window.location.href, null);
}, Math.max(1, Number(modal.dataset.autoWait) || 5) * 1000);
}
}
if (window.AksrtFrontend && typeof window.AksrtFrontend.register === 'function') {
window.AksrtFrontend.register('aksrt-auth', function (root) {
initGlobal();
initRoot(root);
initModal();
});
}
}());
+63 -27
View File
@@ -13,14 +13,30 @@
(function () {
'use strict';
var globalEventsBound = false;
function elementsIn(root, selector) {
var elements = [];
root = root || document;
if (root.nodeType === 1 && root.matches(selector)) elements.push(root);
if (root.querySelectorAll) root.querySelectorAll(selector).forEach(function (element) { elements.push(element); });
return elements;
}
function elementById(root, id) {
root = root || document;
if (root.nodeType === 1 && root.id === id) return root;
return root.querySelector ? root.querySelector('#' + id) : null;
}
function notifyLoadError() {
if (typeof notyf === 'function') {
notyf('加载失败,请重试', 'danger');
}
}
function initPublicDashboards() {
document.querySelectorAll('.dashboard--public').forEach(function (root) {
function initPublicDashboards(scope) {
elementsIn(scope, '.dashboard--public').forEach(function (root) {
if (root.dataset.aksrtAuthorBound === '1') return;
root.dataset.aksrtAuthorBound = '1';
@@ -138,13 +154,13 @@
});
}
function initCoverUpload() {
function initCoverUpload(root) {
var cfg = window.aksrtAuthorPage || {};
var upload = cfg.coverUpload || null;
if (!upload || !upload.enabled || !upload.restUrl) return;
var btn = document.getElementById(upload.buttonId || 'aksrt-upload-bg-btn');
var input = document.getElementById(upload.inputId || 'aksrt-bg-file-input');
var btn = elementById(root, upload.buttonId || 'aksrt-upload-bg-btn');
var input = elementById(root, upload.inputId || 'aksrt-bg-file-input');
if (!btn || !input || btn.dataset.aksrtCoverBound === '1') return;
btn.dataset.aksrtCoverBound = '1';
@@ -238,13 +254,13 @@
});
}
function initAvatarUpload() {
function initAvatarUpload(root) {
var upload = (window.aksrtUserCenter || {}).avatarUpload;
if (!upload || !upload.enabled || !upload.restUrl) return;
var button = document.getElementById(upload.buttonId || 'aksrt-upload-avatar-btn');
var input = document.getElementById(upload.inputId || 'aksrt-avatar-file-input');
var image = document.getElementById(upload.imageId || 'aksrt-user-avatar-image');
var button = elementById(root, upload.buttonId || 'aksrt-upload-avatar-btn');
var input = elementById(root, upload.inputId || 'aksrt-avatar-file-input');
var image = elementById(root, upload.imageId || 'aksrt-user-avatar-image');
if (!button || !input || button.dataset.aksrtAvatarBound === '1') return;
button.dataset.aksrtAvatarBound = '1';
@@ -297,8 +313,8 @@
});
}
function initCoverMenus() {
document.querySelectorAll('[data-aksrt-menu]').forEach(function (menu) {
function initCoverMenus(root) {
elementsIn(root, '[data-aksrt-menu]').forEach(function (menu) {
if (menu.dataset.aksrtMenuBound === '1') return;
menu.dataset.aksrtMenuBound = '1';
var trigger = menu.querySelector('.aksrt-cover-menu__trigger');
@@ -320,34 +336,54 @@
}
trigger.addEventListener('click', function () { panel.hidden ? open() : close(); });
menu.addEventListener('keydown', function (event) { if (event.key === 'Escape') { close(); trigger.focus(); } });
document.addEventListener('pointerdown', function (event) { if (!menu.contains(event.target)) close(); });
});
}
function initProfileDetailsModal() {
var modal = document.getElementById('aksrt-profile-details-modal');
if (!modal) return;
function initProfileDetailsModal(root) {
var modal = elementById(root, 'aksrt-profile-details-modal');
if (!modal || modal.dataset.aksrtProfileModalBound === '1') return;
modal.dataset.aksrtProfileModalBound = '1';
var dialog = modal.querySelector('.aksrt-profile-details-modal__dialog');
var returnFocus = null;
function close() { modal.hidden = true; if (returnFocus) returnFocus.focus(); }
document.querySelectorAll('[data-aksrt-profile-details]').forEach(function (button) {
elementsIn(root, '[data-aksrt-profile-details]').forEach(function (button) {
button.addEventListener('click', function () { returnFocus = button; modal.hidden = false; if (dialog) dialog.focus(); });
});
modal.querySelectorAll('[data-aksrt-modal-close]').forEach(function (button) { button.addEventListener('click', close); });
document.addEventListener('keydown', function (event) { if (event.key === 'Escape' && !modal.hidden) close(); });
}
function init() {
initPublicDashboards();
initCoverMenus();
initProfileDetailsModal();
initCoverUpload();
initAvatarUpload();
function initGlobalEvents() {
if (globalEventsBound) return;
globalEventsBound = true;
document.addEventListener('pointerdown', function (event) {
document.querySelectorAll('[data-aksrt-menu]').forEach(function (menu) {
if (menu.contains(event.target)) return;
var panel = menu.querySelector('.aksrt-cover-menu__panel');
var trigger = menu.querySelector('.aksrt-cover-menu__trigger');
if (panel) panel.hidden = true;
if (trigger) trigger.setAttribute('aria-expanded', 'false');
});
});
document.addEventListener('keydown', function (event) {
if (event.key !== 'Escape') return;
var modal = document.getElementById('aksrt-profile-details-modal');
if (modal && !modal.hidden) {
var close = modal.querySelector('[data-aksrt-modal-close]');
if (close) close.click();
}
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
function init(root) {
initGlobalEvents();
initPublicDashboards(root);
initCoverMenus(root);
initProfileDetailsModal(root);
initCoverUpload(root);
initAvatarUpload(root);
}
if (window.AksrtFrontend && typeof window.AksrtFrontend.register === 'function') {
window.AksrtFrontend.register('aksrt-author', init);
}
})();
+7 -5
View File
@@ -9,9 +9,12 @@
if (window._win && window._win.ajax_url) return window._win.ajax_url;
return '/wp-admin/admin-ajax.php';
}
function init() {
var form = document.querySelector('.aksrt-ban-appeal-form');
if (!form) return;
function init(root) {
root = root || document;
var form = root.nodeType === 1 && root.matches('.aksrt-ban-appeal-form')
? root : root.querySelector('.aksrt-ban-appeal-form');
if (!form || form.dataset.aksrtBanAppealBound === '1') return;
form.dataset.aksrtBanAppealBound = '1';
form.addEventListener('submit', function (e) {
e.preventDefault();
var btn = form.querySelector('button[type="submit"]');
@@ -32,6 +35,5 @@
.finally(function () { if (btn) btn.disabled = false; });
});
}
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
else init();
window.AksrtFrontend.register('aksrt-ban-appeal-page', init);
})();
+436 -517
View File
File diff suppressed because one or more lines are too long
+6 -11
View File
@@ -121,8 +121,11 @@
TOKEN_FIELDS: TOKEN_FIELDS
});
function scan() {
var mounts = document.querySelectorAll('[data-aksrt-captcha-config]');
function scan(root, reason) {
var scope = root && root.querySelectorAll ? root : document;
var mounts = [];
if (scope.nodeType === 1 && scope.matches('[data-aksrt-captcha-config]')) mounts.push(scope);
Array.prototype.push.apply(mounts, scope.querySelectorAll('[data-aksrt-captcha-config]'));
Array.prototype.forEach.call(mounts, function (mount) {
if (mount.dataset.aksrtCaptchaBound) return;
var config;
@@ -545,13 +548,5 @@
}
}
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', scan);
else setTimeout(scan, 0);
if (window.MutationObserver) {
new MutationObserver(function (mutations) {
var shouldScan = mutations.some(function (mutation) { return mutation.addedNodes && mutation.addedNodes.length; });
if (shouldScan) scan();
}).observe(document.documentElement, { childList: true, subtree: true });
}
window.AksrtFrontend.register('aksrt-captcha-front', scan);
})();
+7 -8
View File
@@ -99,7 +99,8 @@
}
function processImage(img) {
if (img.dataset.aksrtColorDone) return;
if (img.dataset.aksrtColorDone || img.dataset.aksrtColorBound) return;
img.dataset.aksrtColorBound = '1';
// Need crossOrigin for canvas access
if (!img.crossOrigin && img.src.indexOf(window.location.origin) !== 0) {
@@ -127,8 +128,10 @@
}
}
function init() {
document.querySelectorAll('[data-aksrt-color-extract]').forEach(processImage);
function init(root, reason) {
var scope = root && root.querySelectorAll ? root : document;
if (scope.nodeType === 1 && scope.matches('[data-aksrt-color-extract]')) processImage(scope);
scope.querySelectorAll('[data-aksrt-color-extract]').forEach(processImage);
}
// Public API
@@ -139,9 +142,5 @@
init: init
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
window.AksrtFrontend.register('aksrt-color-extract', init);
})();
+38 -26
View File
@@ -39,19 +39,6 @@
}
}
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;
@@ -67,24 +54,49 @@
resize();
}
function scan() {
document.querySelectorAll('textarea[autoheight], textarea.grin').forEach(bindAutoheight);
function scopeFor(root) {
return root && root.querySelectorAll ? root : document;
}
document.addEventListener('DOMContentLoaded', scan);
if (window.AksrtFrontend && typeof window.AksrtFrontend.register === 'function') {
window.AksrtFrontend.register('aksrt-comment-fixed-input', function (root) {
scan();
// Expose for submit hide.
root = root || document;
var respond = root.querySelector ? root.querySelector('#respond') : document.getElementById('respond');
if (respond) {
respond.aksrtFixedInput = function (action) {
FixedInput(respond, action);
};
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'));
if (respond) {
respond.aksrtFixedInput = function (action) {
FixedInput(respond, action);
};
}
});
window.AksrtFixedInput = FixedInput;
})();
+48 -59
View File
@@ -4,6 +4,18 @@
(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;
@@ -32,26 +44,15 @@
}
function initGradientBackgrounds(root) {
var scope = root || document;
if (scope.nodeType === 1 && scope.matches(".gradient-bg")) {
renderGradientBackground(scope);
}
scope.querySelectorAll(".gradient-bg").forEach(renderGradientBackground);
eachMatch(root, ".gradient-bg", 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) {
var scope = root || document;
scope.querySelectorAll("[data-post-thumb-video]").forEach(function (box) {
eachMatch(root, "[data-post-thumb-video]", 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) {
@@ -82,25 +83,17 @@
});
}
window.AksrtFrontend.register("aksrt-post-thumb-media", function (root) {
initPostThumbMedia(root);
initGradientBackgrounds(root);
});
})();
(function () {
"use strict";
function initSlideCovers() {
var covers = document.querySelectorAll(".single-cover--slide");
covers.forEach(function (cover) {
function initSlideCovers(root) {
eachMatch(root, ".single-cover--slide", function (cover) {
if (cover.dataset.aksrtSlideCoverBound === "1") return;
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");
@@ -110,33 +103,32 @@
if (dots[current]) dots[current].classList.add("is-active");
}
var timer = setInterval(function () {
goTo((current + 1) % slides.length);
}, interval);
function startTimer() {
timer = window.setInterval(function () {
goTo((current + 1) % slides.length);
}, interval);
}
startTimer();
dots.forEach(function (dot, i) {
dot.addEventListener("click", function () {
clearInterval(timer);
window.clearInterval(timer);
goTo(i);
timer = setInterval(function () {
goTo((current + 1) % slides.length);
}, interval);
startTimer();
});
});
});
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initSlideCovers);
} else {
initSlideCovers();
}
})();
function bindGlobals() {
if (globalsBound) return;
globalsBound = true;
(function () {
"use strict";
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 initHiddenContent() {
document.addEventListener("click", function (e) {
var btn = e.target.closest(".aksrt-hidden-content__submit-btn");
if (!btn) return;
@@ -157,7 +149,7 @@
var formData = new FormData();
formData.append("action", "aksrt_check_visibility");
formData.append("_nonce", (window.aksrtData && aksrtData.visibilityNonce) || "");
formData.append("_nonce", (window.aksrtData && window.aksrtData.visibilityNonce) || "");
formData.append("mode", mode);
formData.append("pid", pid);
if (password) formData.append("password", password);
@@ -165,7 +157,7 @@
btn.disabled = true;
btn.textContent = "...";
fetch((window.aksrtData && aksrtData.ajaxUrl) || "/wp-admin/admin-ajax.php", {
fetch((window.aksrtData && window.aksrtData.ajaxUrl) || "/wp-admin/admin-ajax.php", {
method: "POST",
body: formData,
credentials: "same-origin",
@@ -188,22 +180,19 @@
});
});
// Handle Enter key on password input
document.addEventListener("keydown", function (e) {
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();
}
}
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 (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initHiddenContent);
} else {
initHiddenContent();
}
window.AksrtFrontend.register("aksrt-misc", function (root, reason) {
bindGlobals();
initPostThumbMedia(root);
initGradientBackgrounds(root);
initSlideCovers(root);
});
})();
+68 -55
View File
@@ -15,6 +15,21 @@
return;
}
var activePoll = null;
var balancesRefreshed = false;
function elementsIn(root, selector) {
var elements = [];
root = root || document;
if (root.nodeType === 1 && root.matches(selector)) elements.push(root);
if (root.querySelectorAll) root.querySelectorAll(selector).forEach(function (element) { elements.push(element); });
return elements;
}
function firstIn(root, selector) {
root = root || document;
if (root.nodeType === 1 && root.matches(selector)) return root;
return root.querySelector ? root.querySelector(selector) : null;
}
function operationKey(owner) {
if (!owner.dataset.aksrtOperationKey) {
@@ -89,8 +104,12 @@
}
// Task-list "去签到" → scroll + click the real asset-card sign-in button.
function initSigninGoto() {
document.querySelectorAll('[data-aksrt-signin-goto]').forEach(function (el) {
function initSigninGoto(root) {
root = root || document;
var items = [];
if (root.nodeType === 1 && root.matches('[data-aksrt-signin-goto]')) items.push(root);
if (root.querySelectorAll) root.querySelectorAll('[data-aksrt-signin-goto]').forEach(function (el) { items.push(el); });
items.forEach(function (el) {
if (el.dataset.aksrtSigninGotoInitialized === '1') return;
el.dataset.aksrtSigninGotoInitialized = '1';
el.addEventListener('click', function (e) {
@@ -113,8 +132,8 @@
}
// ===== Forward-only affiliate revenue center =====
function initAffiliateRevenue() {
var root = document.querySelector('[data-aksrt-revenue-page]');
function initAffiliateRevenue(scope) {
var root = firstIn(scope, '[data-aksrt-revenue-page]');
if (!root || root.dataset.affiliateBound) return;
root.dataset.affiliateBound = '1';
var input = root.querySelector('[data-affiliate-link]');
@@ -149,9 +168,10 @@
// ===== VIP 积分兑换 =====
function initVipPointsExchange() {
var root = document.querySelector('[data-aksrt-vip-points]');
if (!root) return;
function initVipPointsExchange(scope) {
var root = firstIn(scope, '[data-aksrt-vip-points]');
if (!root || root.dataset.aksrtVipPointsBound === '1') return;
root.dataset.aksrtVipPointsBound = '1';
var tip = root.querySelector('[data-aksrt-vip-points-tip]');
var busy = false;
var coordinator = window.AksrtVipPurchaseCoordinator;
@@ -191,9 +211,10 @@
}
// ===== VIP 开通 =====
function initVipShop() {
var root = document.querySelector('[data-aksrt-vip-shop]');
if (!root) return;
function initVipShop(scope) {
var root = firstIn(scope, '[data-aksrt-vip-shop]');
if (!root || root.dataset.aksrtVipShopBound === '1') return;
root.dataset.aksrtVipShopBound = '1';
var tip = root.querySelector('[data-aksrt-vip-tip]');
var busy = false;
var coordinator = window.AksrtVipPurchaseCoordinator;
@@ -265,11 +286,13 @@
}
// ===== 卡密兑换(余额 / 会员) =====
function initCardPass() {
var roots = document.querySelectorAll('[data-aksrt-card-pass]');
function initCardPass(scope) {
var roots = elementsIn(scope, '[data-aksrt-card-pass]');
if (!roots || !roots.length) return;
Array.prototype.forEach.call(roots, function (root) {
if (root.dataset.aksrtCardPassBound === '1') return;
root.dataset.aksrtCardPassBound = '1';
var tip = root.querySelector('[data-aksrt-card-tip]');
var busy = false;
resetOperationKeyOnChange(root);
@@ -380,8 +403,8 @@
return handle;
}
function initBalanceCharge() {
var modal = document.querySelector('[data-aksrt-charge-modal]');
function initBalanceCharge(scope) {
var modal = firstIn(scope, '[data-aksrt-charge-modal]');
if (!modal || modal.dataset.aksrtChargeInitialized === '1') return;
modal.dataset.aksrtChargeInitialized = '1';
var form = modal.querySelector('[data-aksrt-charge-form]');
@@ -458,8 +481,8 @@
});
}
function initTransfer() {
var modal = document.querySelector('[data-aksrt-transfer-modal]');
function initTransfer(scope) {
var modal = firstIn(scope, '[data-aksrt-transfer-modal]');
if (!modal || modal.dataset.aksrtTransferInitialized === '1') return;
modal.dataset.aksrtTransferInitialized = '1';
var form = modal.querySelector('[data-aksrt-transfer-form]');
@@ -590,8 +613,8 @@
});
}
function initPointsExchange() {
var modal = document.querySelector('[data-aksrt-points-exchange-modal]');
function initPointsExchange(scope) {
var modal = firstIn(scope, '[data-aksrt-points-exchange-modal]');
if (!modal || modal.dataset.aksrtPointsExchangeInitialized === '1') return;
modal.dataset.aksrtPointsExchangeInitialized = '1';
var form = modal.querySelector('[data-aksrt-points-exchange-form]');
@@ -650,8 +673,8 @@
});
}
function initWithdraw() {
var modal = document.querySelector('[data-aksrt-withdraw-modal]');
function initWithdraw(scope) {
var modal = firstIn(scope, '[data-aksrt-withdraw-modal]');
if (!modal || modal.dataset.aksrtWithdrawInitialized === '1') return;
modal.dataset.aksrtWithdrawInitialized = '1';
var form = modal.querySelector('[data-aksrt-withdraw-form]');
@@ -735,27 +758,28 @@
});
}
function initAssetTabs() {
var nav = document.querySelectorAll('[data-aksrt-asset-tab]');
function initAssetTabs(root) {
var nav = elementsIn(root, '[data-aksrt-asset-tab]');
if (!nav.length) return;
var scope = root || document;
nav.forEach(function (link) {
if (link.dataset.aksrtAssetTabBound === 'true') return;
link.dataset.aksrtAssetTabBound = 'true';
link.addEventListener('click', function (e) {
e.preventDefault();
var key = link.getAttribute('data-aksrt-asset-tab');
document.querySelectorAll('.uc-asset-tabs__nav [data-aksrt-asset-tab]').forEach(function (a) {
elementsIn(scope, '[data-aksrt-asset-tab]').forEach(function (a) {
var li = a.closest('li');
if (!li) return;
var aKey = a.getAttribute('data-aksrt-asset-tab');
var on = aKey === key || (key === 'points_date' && aKey === 'points_free');
li.classList.toggle('active', on);
});
var tabs = document.querySelector('.uc-asset-tabs');
var tabs = firstIn(scope, '.uc-asset-tabs');
if (tabs && typeof tabs.scrollIntoView === 'function') {
tabs.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
document.querySelectorAll('[data-aksrt-asset-pane]').forEach(function (pane) {
elementsIn(scope, '[data-aksrt-asset-pane]').forEach(function (pane) {
var on = pane.getAttribute('data-aksrt-asset-pane') === key;
pane.classList.toggle('is-active', on);
pane.hidden = !on;
@@ -765,8 +789,8 @@
}
function initWithdrawHistory() {
var modal = document.querySelector('[data-aksrt-withdraw-history-modal]');
function initWithdrawHistory(scope) {
var modal = firstIn(scope, '[data-aksrt-withdraw-history-modal]');
if (!modal || modal.dataset.aksrtWithdrawHistoryInitialized === '1') return;
modal.dataset.aksrtWithdrawHistoryInitialized = '1';
function open() { modal.hidden = false; document.body.classList.add('uc-modal-open'); }
@@ -785,36 +809,25 @@
refresh: refreshAssetBalances
};
function bootAssets() {
refreshAssetBalances();
initSigninGoto();
initAffiliateRevenue();
initVipShop();
initVipPointsExchange();
initCardPass();
initBalanceCharge();
initTransfer();
initPointsExchange();
initWithdraw();
initWithdrawHistory();
initAssetTabs();
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', bootAssets);
} else {
bootAssets();
function bootAssets(root, reason) {
if (!balancesRefreshed && reason === 'init') {
balancesRefreshed = true;
refreshAssetBalances();
}
initSigninGoto(root);
initAffiliateRevenue(root);
initVipShop(root);
initVipPointsExchange(root);
initCardPass(root);
initBalanceCharge(root);
initTransfer(root);
initPointsExchange(root);
initWithdraw(root);
initWithdrawHistory(root);
initAssetTabs(root);
}
if (window.AksrtFrontend && typeof window.AksrtFrontend.register === 'function') {
window.AksrtFrontend.register('credits', function () {
initSigninGoto();
initBalanceCharge();
initTransfer();
initPointsExchange();
initWithdraw();
initWithdrawHistory();
initAssetTabs();
});
window.AksrtFrontend.register('credits', bootAssets);
}
})();
+9 -8
View File
@@ -18,9 +18,12 @@
searchInput: null,
items: [],
init: function () {
this.sidebar = document.querySelector('.aksrt-doc-sidebar');
if (!this.sidebar) return;
init: function (root) {
root = root || document;
this.sidebar = root.nodeType === 1 && root.matches('.aksrt-doc-sidebar')
? root : root.querySelector('.aksrt-doc-sidebar');
if (!this.sidebar || this.sidebar.dataset.aksrtDocsNavBound === '1') return;
this.sidebar.dataset.aksrtDocsNavBound = '1';
this.items = Array.from(this.sidebar.querySelectorAll('.aksrt-doc-sidebar__item'));
this.searchInput = this.sidebar.querySelector('.aksrt-doc-sidebar__search-input');
@@ -129,9 +132,7 @@
},
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function () { DocsNav.init(); });
} else {
DocsNav.init();
}
window.AksrtFrontend.register('aksrt-docs-navigation', function (root) {
DocsNav.init(root);
});
})();
+13 -8
View File
@@ -13,7 +13,8 @@
'use strict';
var DownloadStatus = {
init: function () {
init: function (root) {
this.root = root || document;
this.initFilterHighlight();
this.initCardHover();
},
@@ -22,10 +23,13 @@
* Animate filter button active state
*/
initFilterHighlight: function () {
var filters = document.querySelectorAll('.aksrt-download-hero__filter');
var filters = this.root.nodeType === 1 && this.root.matches('.aksrt-download-hero__filter')
? [this.root] : this.root.querySelectorAll('.aksrt-download-hero__filter');
if (filters.length === 0) return;
filters.forEach(function (btn) {
if (btn.dataset.aksrtDownloadHoverBound === '1') return;
btn.dataset.aksrtDownloadHoverBound = '1';
btn.addEventListener('mouseenter', function () {
btn.style.transform = 'translateY(-1px)';
});
@@ -39,10 +43,13 @@
* Card hover depth effect
*/
initCardHover: function () {
var cards = document.querySelectorAll('.aksrt-download-card');
var cards = this.root.nodeType === 1 && this.root.matches('.aksrt-download-card')
? [this.root] : this.root.querySelectorAll('.aksrt-download-card');
if (cards.length === 0) return;
cards.forEach(function (card) {
if (card.dataset.aksrtDownloadHoverBound === '1') return;
card.dataset.aksrtDownloadHoverBound = '1';
card.addEventListener('mouseenter', function () {
card.style.transform = 'translateY(-2px)';
});
@@ -53,9 +60,7 @@
},
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function () { DownloadStatus.init(); });
} else {
DownloadStatus.init();
}
window.AksrtFrontend.register('aksrt-download-status', function (root) {
DownloadStatus.init(root);
});
})();
+91 -114
View File
@@ -10,108 +10,101 @@
'use strict';
var reducedMotion = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
var countUpObserver = null;
var countdownElements = [];
var countdownTimer = null;
var fpsDetectionStarted = false;
/* ============================================================
* 1. 数字递增 (count-up) — IntersectionObserver 触发
* 用法:<span data-aksrt-countup data-target="1234" data-duration="2000">0</span>
* ============================================================ */
function initCountUp() {
if (reducedMotion) return;
if (!('IntersectionObserver' in window)) return;
function scopeFor(root) {
return root && root.querySelectorAll ? root : document;
}
var els = document.querySelectorAll('[data-aksrt-countup]');
if (!els.length) return;
function eachMatch(root, selector, callback) {
var scope = scopeFor(root);
if (scope.nodeType === 1 && scope.matches(selector)) callback(scope);
scope.querySelectorAll(selector).forEach(callback);
}
var observer = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (!entry.isIntersecting) return;
var el = entry.target;
observer.unobserve(el);
function animateCountUp(el) {
if (el.dataset.aksrtCountupBound === '1') return;
el.dataset.aksrtCountupBound = '1';
countUpObserver.observe(el);
}
var target = parseFloat(el.dataset.target || '0');
var duration = parseInt(el.dataset.duration || '2000', 10);
var decimals = (el.dataset.decimals || '0|').split('|');
var prefix = decimals[1] || '';
var dec = parseInt(decimals[0], 10) || 0;
var start = 0;
var startTime = null;
function initCountUp(root) {
if (reducedMotion || !('IntersectionObserver' in window)) return;
if (!countUpObserver) {
countUpObserver = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (!entry.isIntersecting) return;
var el = entry.target;
countUpObserver.unobserve(el);
var target = parseFloat(el.dataset.target || '0');
var duration = parseInt(el.dataset.duration || '2000', 10);
var decimals = (el.dataset.decimals || '0|').split('|');
var prefix = decimals[1] || '';
var dec = parseInt(decimals[0], 10) || 0;
var startTime = null;
function step(timestamp) {
if (!startTime) startTime = timestamp;
var progress = Math.min((timestamp - startTime) / duration, 1);
// ease-out cubic
var eased = 1 - Math.pow(1 - progress, 3);
var current = start + (target - start) * eased;
el.textContent = prefix + current.toFixed(dec).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
if (progress < 1) {
requestAnimationFrame(step);
} else {
el.textContent = prefix + target.toFixed(dec).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
function step(timestamp) {
if (!startTime) startTime = timestamp;
var progress = Math.min((timestamp - startTime) / duration, 1);
var current = target * (1 - Math.pow(1 - progress, 3));
el.textContent = prefix + current.toFixed(dec).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
if (progress < 1) requestAnimationFrame(step);
else el.textContent = prefix + target.toFixed(dec).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}
}
requestAnimationFrame(step);
});
}, { threshold: 0.3 });
els.forEach(function (el) { observer.observe(el); });
}
/* ============================================================
* 2. 倒计时组件
* 用法:<span data-aksrt-countdown data-end="2026-12-31T23:59:59">--:--:--</span>
* ============================================================ */
function initCountdown() {
var els = document.querySelectorAll('[data-aksrt-countdown]');
if (!els.length) return;
function pad(n) { return n < 10 ? '0' + n : '' + n; }
function update() {
var now = Date.now();
els.forEach(function (el) {
var end = new Date(el.dataset.end).getTime();
var diff = end - now;
if (diff <= 0) {
el.textContent = el.dataset.expired || '已结束';
return;
}
var d = Math.floor(diff / 86400000);
var h = Math.floor((diff % 86400000) / 3600000);
var m = Math.floor((diff % 3600000) / 60000);
var s = Math.floor((diff % 60000) / 1000);
var format = el.dataset.format || 'dhms';
if (format === 'dhms') {
el.textContent = (d > 0 ? d + '天 ' : '') + pad(h) + ':' + pad(m) + ':' + pad(s);
} else if (format === 'hms') {
el.textContent = pad(h + d * 24) + ':' + pad(m) + ':' + pad(s);
} else {
el.textContent = (d > 0 ? d + '天 ' : '') + pad(h) + '时' + pad(m) + '分' + pad(s) + '秒';
}
});
requestAnimationFrame(step);
});
}, { threshold: 0.3 });
}
update();
setInterval(update, 1000);
eachMatch(root, '[data-aksrt-countup]', animateCountUp);
}
/* ============================================================
* 4. 3D 悬停倾斜 (vanilla tilt)
* 用法:<div data-aksrt-tilt data-tilt-max="15">...</div>
* ============================================================ */
function initTilt() {
if (reducedMotion) return;
function pad(n) { return n < 10 ? '0' + n : '' + n; }
document.querySelectorAll('[data-aksrt-tilt]').forEach(function (el) {
function updateCountdowns() {
var now = Date.now();
countdownElements = countdownElements.filter(function (el) { return document.documentElement.contains(el); });
countdownElements.forEach(function (el) {
var end = new Date(el.dataset.end).getTime();
var diff = end - now;
if (diff <= 0) {
el.textContent = el.dataset.expired || '已结束';
return;
}
var d = Math.floor(diff / 86400000);
var h = Math.floor((diff % 86400000) / 3600000);
var m = Math.floor((diff % 3600000) / 60000);
var s = Math.floor((diff % 60000) / 1000);
var format = el.dataset.format || 'dhms';
if (format === 'dhms') el.textContent = (d > 0 ? d + '天 ' : '') + pad(h) + ':' + pad(m) + ':' + pad(s);
else if (format === 'hms') el.textContent = pad(h + d * 24) + ':' + pad(m) + ':' + pad(s);
else el.textContent = (d > 0 ? d + '天 ' : '') + pad(h) + '时' + pad(m) + '分' + pad(s) + '秒';
});
}
function initCountdown(root) {
eachMatch(root, '[data-aksrt-countdown]', function (el) {
if (el.dataset.aksrtCountdownBound === '1') return;
el.dataset.aksrtCountdownBound = '1';
countdownElements.push(el);
});
updateCountdowns();
if (!countdownTimer && countdownElements.length) countdownTimer = window.setInterval(updateCountdowns, 1000);
}
function initTilt(root) {
if (reducedMotion) return;
eachMatch(root, '[data-aksrt-tilt]', function (el) {
if (el.dataset.tiltBound) return;
el.dataset.tiltBound = '1';
var maxDeg = parseFloat(el.dataset.tiltMax || '10');
var perspective = parseFloat(el.dataset.tiltPerspective || '800');
var scale = parseFloat(el.dataset.tiltScale || '1.03');
var glare = el.dataset.tiltGlare === '1';
var glareEl = null;
if (glare) {
glareEl = document.createElement('div');
glareEl.style.cssText = 'position:absolute;inset:0;border-radius:inherit;pointer-events:none;background:linear-gradient(135deg,rgba(255,255,255,0) 0%,rgba(255,255,255,0.25) 100%);opacity:0;transition:opacity 0.2s;';
@@ -119,17 +112,13 @@
el.style.overflow = 'hidden';
el.appendChild(glareEl);
}
el.addEventListener('mousemove', function (e) {
var rect = el.getBoundingClientRect();
var x = (e.clientX - rect.left) / rect.width;
var y = (e.clientY - rect.top) / rect.height;
var rotateX = (0.5 - y) * maxDeg;
var rotateY = (x - 0.5) * maxDeg;
el.style.transform = 'perspective(' + perspective + 'px) rotateX(' + rotateX + 'deg) rotateY(' + rotateY + 'deg) scale3d(' + scale + ',' + scale + ',' + scale + ')';
el.style.transform = 'perspective(' + perspective + 'px) rotateX(' + ((0.5 - y) * maxDeg) + 'deg) rotateY(' + ((x - 0.5) * maxDeg) + 'deg) scale3d(' + scale + ',' + scale + ',' + scale + ')';
if (glareEl) glareEl.style.opacity = '1';
});
el.addEventListener('mouseleave', function () {
el.style.transform = 'perspective(' + perspective + 'px) rotateX(0deg) rotateY(0deg) scale3d(1,1,1)';
if (glareEl) glareEl.style.opacity = '0';
@@ -137,42 +126,30 @@
});
}
/* ============================================================
* 5. FPS 检测 + 低端设备降级
* ============================================================ */
function initFpsDetection() {
if (!('requestAnimationFrame' in window)) return;
function initFpsDetection(root, reason) {
if (fpsDetectionStarted || !('requestAnimationFrame' in window)) return;
fpsDetectionStarted = true;
var frames = 0;
var startTime = performance.now();
function countFrames() {
frames++;
var elapsed = performance.now() - startTime;
if (elapsed >= 1000) {
var fps = Math.round(frames * 1000 / elapsed);
if (fps < 24) {
document.body.classList.add('fps-accelerat');
}
return; // 只检测一次
if (Math.round(frames * 1000 / elapsed) < 24 && document.body) document.body.classList.add('fps-accelerat');
return;
}
requestAnimationFrame(countFrames);
}
requestAnimationFrame(countFrames);
}
/* ============================================================
* 初始化入口
* ============================================================ */
document.addEventListener('DOMContentLoaded', function () {
initCountUp();
initCountdown();
if (typeof initMarquee === 'function') {
initMarquee();
}
initTilt();
initFpsDetection();
});
function init(root, reason) {
initCountUp(root);
initCountdown(root);
if (typeof initMarquee === 'function') initMarquee(root, reason);
initTilt(root);
initFpsDetection(root, reason);
}
window.AksrtFrontend.register('aksrt-effects', init);
})();
+11 -5
View File
@@ -21,6 +21,8 @@
var isAutoplay = false;
var lastTrigger = null;
var previousBodyOverflow = '';
var globalsBound = false;
var scrollDirectionBound = false;
var EXCLUDE_SEL = '.no-imgbox,.no-lightbox,.avatar,.img-icon,.avatar-badge,.aksrt-avatar,[data-no-lightbox],[data-aksrt-lightbox="0"]';
var TRIGGER_SEL = '[data-aksrt-lightbox="1"] img,.aksrt-lightbox-trigger img,.imgbox-container img,.comment-content .box-img';
var ANCHOR_TRIGGER_SEL = 'a[data-aksrt-lightbox-trigger]';
@@ -496,7 +498,9 @@
return openLightbox(item.fullSrc, item.caption, gallery.items, gallery.index, img);
}
function initLightbox() {
function initLightbox(root, reason) {
if (globalsBound) return;
globalsBound = true;
document.addEventListener('click', function (event) {
if (!lightboxEnabled() || !(event.target instanceof Element)) return;
@@ -527,7 +531,9 @@
// Scroll direction is handled by aksrt-runtime.js. Keep the prefixed
// classes in sync for the remaining CSS consumers.
function initScrollDirection() {
function initScrollDirection(root, reason) {
if (scrollDirectionBound || !document.body) return;
scrollDirectionBound = true;
var body = document.body;
function sync() {
@@ -547,8 +553,8 @@
}, { passive: true });
}
document.addEventListener('DOMContentLoaded', function () {
initLightbox();
initScrollDirection();
window.AksrtFrontend.register('aksrt-enhancements', function (root, reason) {
initLightbox(root, reason);
initScrollDirection(root, reason);
});
})();
+164 -194
View File
@@ -9,11 +9,27 @@
(function () {
'use strict';
/* ============================================================
* 1. 3D 悬停倾斜效果 (vanilla-tilt 轻量版)
* ============================================================ */
function initTilt() {
document.querySelectorAll('[data-aksrt-tilt]').forEach(function (el) {
var animateObserver = null;
var rippleBound = false;
var stickyScrollBound = false;
var parallaxScrollBound = false;
var modalBound = false;
var stickyElements = [];
var parallaxElements = [];
var parallaxTicking = 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 initTilt(root) {
eachMatch(root, '[data-aksrt-tilt]', function (el) {
if (el.dataset.tiltInit) return;
el.dataset.tiltInit = '1';
@@ -58,230 +74,184 @@
});
}
/* ============================================================
* 2. 滚动触发动画 (IntersectionObserver)
* ============================================================ */
function initScrollAnimations() {
function prepareAnimation(el) {
if (el.dataset.aksrtAnimateBound === '1') return;
el.dataset.aksrtAnimateBound = '1';
var animation = el.dataset.aksrtAnimate || 'fadeInUp';
el.style.opacity = '0';
switch (animation) {
case 'fadeIn': el.style.transform = 'none'; break;
case 'fadeInUp': el.style.transform = 'translateY(30px)'; break;
case 'fadeInDown': el.style.transform = 'translateY(-30px)'; break;
case 'fadeInLeft': el.style.transform = 'translateX(-30px)'; break;
case 'fadeInRight': el.style.transform = 'translateX(30px)'; break;
case 'zoomIn': el.style.transform = 'scale(0.9)'; break;
default: el.style.transform = 'translateY(30px)';
}
animateObserver.observe(el);
}
function initScrollAnimations(root) {
if (!('IntersectionObserver' in window)) {
// 不支持时直接显示所有元素
document.querySelectorAll('[data-aksrt-animate]').forEach(function (el) {
eachMatch(root, '[data-aksrt-animate]', function (el) {
el.style.opacity = '1';
el.style.transform = 'none';
});
return;
}
var observer = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (!entry.isIntersecting) return;
var el = entry.target;
var animation = el.dataset.aksrtAnimate || 'fadeInUp';
var delay = parseInt(el.dataset.aksrtAnimateDelay || '0', 10);
var duration = parseInt(el.dataset.aksrtAnimateDuration || '600', 10);
setTimeout(function () {
el.style.transition = 'opacity ' + duration + 'ms ease, transform ' + duration + 'ms ease';
el.style.opacity = '1';
el.style.transform = 'translateY(0) translateX(0) scale(1)';
el.classList.add('aksrt-animated');
}, delay);
observer.unobserve(el);
});
}, {
threshold: 0.1,
rootMargin: '0px 0px -50px 0px',
});
document.querySelectorAll('[data-aksrt-animate]').forEach(function (el) {
var animation = el.dataset.aksrtAnimate || 'fadeInUp';
// 设置初始状态
el.style.opacity = '0';
switch (animation) {
case 'fadeIn':
el.style.transform = 'none';
break;
case 'fadeInUp':
el.style.transform = 'translateY(30px)';
break;
case 'fadeInDown':
el.style.transform = 'translateY(-30px)';
break;
case 'fadeInLeft':
el.style.transform = 'translateX(-30px)';
break;
case 'fadeInRight':
el.style.transform = 'translateX(30px)';
break;
case 'zoomIn':
el.style.transform = 'scale(0.9)';
break;
default:
el.style.transform = 'translateY(30px)';
}
observer.observe(el);
});
}
/* ============================================================
* 5. 粘性元素 (Sticky)
* ============================================================ */
function initSticky() {
document.querySelectorAll('[data-aksrt-sticky]').forEach(function (el) {
var top = parseInt(el.dataset.aksrtStickyTop || '80', 10);
var offset = parseInt(el.dataset.aksrtStickyOffset || '0', 10);
function update() {
var rect = el.getBoundingClientRect();
var parentRect = el.parentElement.getBoundingClientRect();
if (parentRect.top < top && parentRect.bottom > el.offsetHeight + top) {
el.style.position = 'sticky';
el.style.top = top + 'px';
}
}
window.addEventListener('scroll', update, { passive: true });
});
}
/* ============================================================
* 6. 视差滚动
* ============================================================ */
function initParallax() {
var elements = document.querySelectorAll('[data-aksrt-parallax]');
if (elements.length === 0) return;
var ticking = false;
function update() {
var scrollTop = window.pageYOffset;
elements.forEach(function (el) {
var speed = parseFloat(el.dataset.aksrtParallax || '0.3');
var rect = el.getBoundingClientRect();
var center = rect.top + rect.height / 2;
var windowCenter = window.innerHeight / 2;
var offset = (center - windowCenter) * speed;
el.style.transform = 'translateY(' + offset + 'px)';
});
ticking = false;
if (!animateObserver) {
animateObserver = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (!entry.isIntersecting) return;
var el = entry.target;
var delay = parseInt(el.dataset.aksrtAnimateDelay || '0', 10);
var duration = parseInt(el.dataset.aksrtAnimateDuration || '600', 10);
animateObserver.unobserve(el);
window.setTimeout(function () {
el.style.transition = 'opacity ' + duration + 'ms ease, transform ' + duration + 'ms ease';
el.style.opacity = '1';
el.style.transform = 'translateY(0) translateX(0) scale(1)';
el.classList.add('aksrt-animated');
}, delay);
});
}, { threshold: 0.1, rootMargin: '0px 0px -50px 0px' });
}
window.addEventListener('scroll', function () {
if (!ticking) {
requestAnimationFrame(update);
ticking = true;
}
}, { passive: true });
eachMatch(root, '[data-aksrt-animate]', prepareAnimation);
}
/* ============================================================
* 7. 涟漪点击效果
* ============================================================ */
function initRipple() {
function updateSticky() {
stickyElements = stickyElements.filter(function (el) { return document.documentElement.contains(el); });
stickyElements.forEach(function (el) {
var top = parseInt(el.dataset.aksrtStickyTop || '80', 10);
var parent = el.parentElement;
if (!parent) return;
var parentRect = parent.getBoundingClientRect();
if (parentRect.top < top && parentRect.bottom > el.offsetHeight + top) {
el.style.position = 'sticky';
el.style.top = top + 'px';
}
});
}
function initSticky(root) {
eachMatch(root, '[data-aksrt-sticky]', function (el) {
if (el.dataset.aksrtStickyBound === '1') return;
el.dataset.aksrtStickyBound = '1';
stickyElements.push(el);
});
if (!stickyScrollBound) {
stickyScrollBound = true;
window.addEventListener('scroll', updateSticky, { passive: true });
}
updateSticky();
}
function updateParallax() {
parallaxElements = parallaxElements.filter(function (el) { return document.documentElement.contains(el); });
parallaxElements.forEach(function (el) {
var speed = parseFloat(el.dataset.aksrtParallax || '0.3');
var rect = el.getBoundingClientRect();
var center = rect.top + rect.height / 2;
var offset = (center - window.innerHeight / 2) * speed;
el.style.transform = 'translateY(' + offset + 'px)';
});
parallaxTicking = false;
}
function initParallax(root) {
eachMatch(root, '[data-aksrt-parallax]', function (el) {
if (el.dataset.aksrtParallaxBound === '1') return;
el.dataset.aksrtParallaxBound = '1';
parallaxElements.push(el);
});
if (!parallaxScrollBound) {
parallaxScrollBound = true;
window.addEventListener('scroll', function () {
if (parallaxTicking) return;
parallaxTicking = true;
requestAnimationFrame(updateParallax);
}, { passive: true });
}
updateParallax();
}
function initRipple(root, reason) {
if (rippleBound) return;
rippleBound = true;
document.addEventListener('click', function (e) {
var el = e.target.closest('.aksrt-ripple');
if (!el) return;
var rect = el.getBoundingClientRect();
var x = e.clientX - rect.left;
var y = e.clientY - rect.top;
var size = Math.max(rect.width, rect.height) * 2;
var wave = document.createElement('span');
wave.className = 'aksrt-ripple__wave';
wave.style.width = wave.style.height = size + 'px';
wave.style.left = (x - size / 2) + 'px';
wave.style.top = (y - size / 2) + 'px';
wave.style.left = (e.clientX - rect.left - size / 2) + 'px';
wave.style.top = (e.clientY - rect.top - size / 2) + 'px';
el.appendChild(wave);
wave.addEventListener('animationend', function () {
wave.remove();
});
wave.addEventListener('animationend', function () { wave.remove(); });
});
}
/* ============================================================
* 8. 表单浮动标签自动初始化
* ============================================================ */
function initFloatLabels() {
document.querySelectorAll('.aksrt-float-label__input').forEach(function (input) {
// 检查初始值
if (input.value) {
input.setAttribute('data-has-value', '1');
}
function initFloatLabels(root) {
eachMatch(root, '.aksrt-float-label__input', function (input) {
if (input.value) input.setAttribute('data-has-value', '1');
if (input.dataset.aksrtFloatLabelBound === '1') return;
input.dataset.aksrtFloatLabelBound = '1';
input.addEventListener('input', function () {
if (this.value) {
this.setAttribute('data-has-value', '1');
} else {
this.removeAttribute('data-has-value');
}
if (this.value) this.setAttribute('data-has-value', '1');
else this.removeAttribute('data-has-value');
});
});
}
/* ============================================================
* 8. 签到日历可视化
* ============================================================ */
function initSigninCalendar() {
var calendar = document.querySelector('[data-aksrt-signin-calendar]');
if (!calendar) return;
var data = [];
try {
data = JSON.parse(calendar.dataset.aksrtSigninCalendar || '[]');
} catch (e) {}
// 生成最近 30 天的格子
var today = new Date();
var html = '<div class="aksrt-signin-calendar__grid">';
for (var i = 29; i >= 0; i--) {
var d = new Date(today);
d.setDate(d.getDate() - i);
var dateStr = d.toISOString().split('T')[0];
var isSigned = data.indexOf(dateStr) !== -1;
var isToday = i === 0;
html += '<div class="aksrt-signin-calendar__day' +
(isSigned ? ' is-signed' : '') +
(isToday ? ' is-today' : '') +
'" title="' + dateStr + (isSigned ? ' ✓' : '') + '">' +
'<span>' + d.getDate() + '</span>' +
'</div>';
}
html += '</div>';
calendar.innerHTML = html;
function initSigninCalendar(root) {
eachMatch(root, '[data-aksrt-signin-calendar]', function (calendar) {
if (calendar.dataset.aksrtSigninCalendarBound === '1') return;
calendar.dataset.aksrtSigninCalendarBound = '1';
var data = [];
try { data = JSON.parse(calendar.dataset.aksrtSigninCalendar || '[]'); } catch (e) {}
var today = new Date();
var html = '<div class="aksrt-signin-calendar__grid">';
for (var i = 29; i >= 0; i--) {
var d = new Date(today);
d.setDate(d.getDate() - i);
var dateStr = d.toISOString().split('T')[0];
var isSigned = data.indexOf(dateStr) !== -1;
html += '<div class="aksrt-signin-calendar__day' + (isSigned ? ' is-signed' : '') + (i === 0 ? ' is-today' : '') +
'" title="' + dateStr + (isSigned ? ' ✓' : '') + '"><span>' + d.getDate() + '</span></div>';
}
calendar.innerHTML = html + '</div>';
});
}
/* ============================================================
* 初始化入口
* ============================================================ */
document.addEventListener('DOMContentLoaded', function () {
initTilt();
initScrollAnimations();
initRipple();
initSticky();
initParallax();
initFloatLabels();
initSigninCalendar();
document.addEventListener('aksrt:modal:open', function () {
// Remote modal may inject calendar markup after open.
window.setTimeout(initSigninCalendar, 30);
function bindModalLifecycle() {
if (modalBound) return;
modalBound = true;
document.addEventListener('aksrt:modal:open', function (event) {
var root = event.target && event.target.querySelectorAll ? event.target : document;
window.setTimeout(function () { initSigninCalendar(root); }, 30);
});
});
}
function init(root, reason) {
initTilt(root);
initScrollAnimations(root);
initRipple(root, reason);
initSticky(root);
initParallax(root);
initFloatLabels(root);
initSigninCalendar(root);
bindModalLifecycle();
}
window.AksrtFrontend.register('aksrt-enhancements-advanced', init);
// 暴露到全局供动态内容使用
window.AksrtEnhancements = {
initTilt: initTilt,
initScrollAnimations: initScrollAnimations,
initRipple: initRipple,
};
})();
+6 -6
View File
@@ -44,7 +44,11 @@
}
}
function initFollowButtons() {
var globalsBound = false;
function initFollowButtons(root, reason) {
if (globalsBound) return;
globalsBound = true;
document.addEventListener('click', function (event) {
var button = event.target.closest('[data-aksrt-follow]');
if (!button) return;
@@ -92,9 +96,5 @@
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initFollowButtons);
} else {
initFollowButtons();
}
window.AksrtFrontend.register('aksrt-follow', initFollowButtons);
})();
+11 -10
View File
@@ -80,11 +80,14 @@
isSubmitting: false,
featured: { type: '', data: {} },
init: function () {
this.form = document.getElementById('aksrt-submit-form');
if (!this.form) {
init: function (root) {
this.root = root || document;
this.form = this.root.nodeType === 1 && this.root.matches('#aksrt-submit-form')
? this.root : this.root.querySelector('#aksrt-submit-form');
if (!this.form || this.form.dataset.aksrtFrontSubmitBound === '1') {
return;
}
this.form.dataset.aksrtFrontSubmitBound = '1';
this.bindDirty();
this.bindAutoHeight();
this.bindSubmitButtons();
@@ -311,6 +314,8 @@
},
bindDraftDelete: function () {
if (document.__aksrtFrontSubmitDraftDeleteBound) return;
document.__aksrtFrontSubmitDraftDeleteBound = true;
document.addEventListener('click', function (e) {
var btn = e.target.closest('.aksrt-submit-drafts__delete');
if (!btn) {
@@ -645,11 +650,7 @@
},
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function () {
App.init();
});
} else {
App.init();
}
window.AksrtFrontend.register('aksrt-front-submit', function (root) {
App.init(root);
});
})();
+21 -17
View File
@@ -424,6 +424,7 @@
var tablists = (scope || document).querySelectorAll('[data-aksrt-home-tabs]');
tablists.forEach(function (list, listIndex) {
if (list.dataset.aksrtHomeTabsBound === '1') return;
var stream = list.closest('.aksrt-homepage__stream');
if (!stream) return;
@@ -431,6 +432,7 @@
var panels = Array.from(stream.querySelectorAll('[data-home-tab-panel]'));
if (buttons.length < 2 || !panels.length) return;
list.dataset.aksrtHomeTabsBound = '1';
function getPanel(button) {
var target = button.getAttribute('data-home-tab-target');
@@ -539,12 +541,14 @@
* Sortbar Dropdown Toggle
* ============================================================ */
function initSortbarDropdown() {
document.querySelectorAll('[data-sort-dropdown-trigger]').forEach(function (trigger) {
function initSortbarDropdown(scope) {
(scope || document).querySelectorAll('[data-sort-dropdown-trigger]').forEach(function (trigger) {
if (trigger.dataset.aksrtSortDropdownBound === '1') return;
var wrapper = trigger.closest('.aksrt-homepage__sortbar-dropdown');
if (!wrapper) return;
var menu = wrapper.querySelector('.aksrt-homepage__sortbar-dropdown-menu');
if (!menu) return;
trigger.dataset.aksrtSortDropdownBound = '1';
function close() {
menu.setAttribute('hidden', '');
@@ -599,10 +603,11 @@
* Sortbar AJAX
* ============================================================ */
function initSortbar() {
document.querySelectorAll('.aksrt-homepage__stream').forEach(function (stream) {
function initSortbar(scope) {
(scope || document).querySelectorAll('.aksrt-homepage__stream').forEach(function (stream) {
var sortbar = stream.querySelector('.aksrt-homepage__sortbar');
if (!sortbar || !isSortAjaxEnabled(sortbar)) return;
if (!sortbar || !isSortAjaxEnabled(sortbar) || sortbar.dataset.aksrtSortbarBound === '1') return;
sortbar.dataset.aksrtSortbarBound = '1';
sortbar.addEventListener('click', function (event) {
var link = event.target.closest('.aksrt-homepage__sortbar-link, .aksrt-homepage__sortbar-dropdown-item');
@@ -649,10 +654,11 @@
return isNaN(offset) ? 60 : offset;
}
function initStickyTabs() {
function initStickyTabs(scope) {
if (!isStickyTabsEnabled()) return;
document.querySelectorAll('.aksrt-homepage__tabs.home-tab-nav-box').forEach(function (tabs) {
(scope || document).querySelectorAll('.aksrt-homepage__tabs.home-tab-nav-box').forEach(function (tabs) {
if (tabs.dataset.aksrtStickyTabsBound === '1') return;
var parent = tabs.parentNode;
var sentinel = tabs.previousElementSibling;
var canUseSticky = supportsStickyPosition();
@@ -660,6 +666,7 @@
var observer = null;
if (!parent || tabs.getAttribute('data-sticky-tabs') === 'false') return;
tabs.dataset.aksrtStickyTabsBound = '1';
if (!sentinel || !sentinel.classList.contains('aksrt-homepage__tabs-sentinel')) {
sentinel = document.createElement('div');
@@ -718,16 +725,13 @@
* Init
* ============================================================ */
function init() {
initHomeTabs();
initSortbarDropdown();
initSortbar();
initStickyTabs();
function init(root) {
var scope = root || document;
initHomeTabs(scope);
initSortbarDropdown(scope);
initSortbar(scope);
initStickyTabs(scope);
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
window.AksrtFrontend.register('aksrt-homepage', init);
})();
+24 -15
View File
@@ -37,9 +37,17 @@
// ── Auto-resize Textarea ──
function initAutoResize() {
var textareas = document.querySelectorAll('textarea[data-aksrt-autoresize]');
function queryAll(root, selector) {
var nodes = Array.prototype.slice.call(root.querySelectorAll(selector));
if (root.nodeType === 1 && root.matches(selector)) nodes.unshift(root);
return nodes;
}
function initAutoResize(root) {
var textareas = queryAll(root, 'textarea[data-aksrt-autoresize]');
textareas.forEach(function (ta) {
if (ta.dataset.aksrtAutoresizeBound === '1') return;
ta.dataset.aksrtAutoresizeBound = '1';
function resize() {
ta.style.height = 'auto';
ta.style.height = ta.scrollHeight + 'px';
@@ -52,9 +60,11 @@
// ── Character Counter ──
function initCounters() {
var fields = document.querySelectorAll('[data-aksrt-counter]');
function initCounters(root) {
var fields = queryAll(root, '[data-aksrt-counter]');
fields.forEach(function (field) {
if (field.dataset.aksrtCounterBound === '1') return;
field.dataset.aksrtCounterBound = '1';
var max = parseInt(field.getAttribute('data-aksrt-maxlength') || field.getAttribute('maxlength') || '0', 10);
var counter = document.createElement('span');
counter.className = 'aksrt-counter';
@@ -79,9 +89,11 @@
// ── Validation Feedback ──
function initValidation() {
var fields = document.querySelectorAll('[data-aksrt-validate]');
function initValidation(root) {
var fields = queryAll(root, '[data-aksrt-validate]');
fields.forEach(function (field) {
if (field.dataset.aksrtValidateBound === '1') return;
field.dataset.aksrtValidateBound = '1';
var minLen = parseInt(field.getAttribute('data-aksrt-minlength') || field.getAttribute('minlength') || '0', 10);
var maxLen = parseInt(field.getAttribute('data-aksrt-maxlength') || field.getAttribute('maxlength') || '0', 10);
var required = field.hasAttribute('required');
@@ -115,16 +127,13 @@
// ── Main Init ──
function init() {
function init(root) {
root = root || document;
injectStyle();
initAutoResize();
initCounters();
initValidation();
initAutoResize(root);
initCounters(root);
initValidation(root);
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
window.AksrtFrontend.register('aksrt-input-expand', init);
})();
-172
View File
@@ -1,172 +0,0 @@
/**
* AKSRT Page Loader
*
* Lightweight top progress bar for page transitions and AJAX requests.
* No external dependencies — pure vanilla JS.
*
* @package AKSRT
*/
(function () {
'use strict';
var STYLE_ID = 'aksrt-loader-style';
var BAR_ID = 'aksrt-loader-bar';
var CSS =
'#' + BAR_ID + '{' +
'position:fixed;top:0;left:0;width:0;height:3px;z-index:99999;' +
'background:linear-gradient(90deg,#1890ff,#36cfc9);' +
'transition:width 0.3s ease,opacity 0.3s ease;' +
'pointer-events:none;opacity:0;' +
'}' +
'#' + BAR_ID + '.is-active{opacity:1;}' +
'#' + BAR_ID + '.is-done{' +
'width:100%!important;opacity:0;' +
'}';
var bar = null;
var timer = null;
var progress = 0;
function injectStyle() {
if (document.getElementById(STYLE_ID)) return;
var style = document.createElement('style');
style.id = STYLE_ID;
style.textContent = CSS;
document.head.appendChild(style);
}
function createBar() {
if (bar) return;
bar = document.createElement('div');
bar.id = BAR_ID;
document.body.appendChild(bar);
}
function start() {
if (!bar) createBar();
clearTimeout(timer);
bar.classList.remove('is-done');
bar.classList.add('is-active');
progress = 0;
bar.style.width = '0%';
trickle();
}
function trickle() {
if (progress >= 90) return;
var increment = progress < 30 ? 8 : progress < 60 ? 4 : 2;
progress = Math.min(90, progress + increment * (0.8 + Math.random() * 0.4));
bar.style.width = progress + '%';
timer = setTimeout(trickle, 200 + Math.random() * 300);
}
function done() {
if (!bar) return;
clearTimeout(timer);
bar.style.width = '100%';
bar.classList.add('is-done');
setTimeout(function () {
bar.classList.remove('is-active', 'is-done');
bar.style.width = '0%';
progress = 0;
}, 400);
}
// Intercept link clicks for same-origin page transitions
function onLinkClick(e) {
if (e.defaultPrevented) return;
if (e.button !== 0) return; // left click only
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
var link = e.target.closest('a');
if (!link || !link.href) return;
if (link.target === '_blank') return;
if (link.hasAttribute('download')) return;
if (link.href.indexOf('#') === 0) return;
// Same-origin only
try {
var url = new URL(link.href);
if (url.origin !== window.location.origin) return;
if (url.protocol !== "http:" && url.protocol !== "https:") return;
if (url.pathname === window.location.pathname && url.search === window.location.search) return;
} catch (ex) { return; }
start();
}
// Intercept form submissions
function onFormSubmit(e) {
var form = e.target;
if (!form || form.tagName !== 'FORM') return;
if (form.target === '_blank') return;
start();
}
// Hook into AJAX (fetch) if available
function hookFetch() {
if (!window.fetch) return;
var origFetch = window.fetch;
window.fetch = function () {
start();
return origFetch.apply(this, arguments).then(function (response) {
done();
return response;
}).catch(function (err) {
done();
throw err;
});
};
}
// Hook into XMLHttpRequest
function hookXHR() {
if (!window.XMLHttpRequest) return;
var origOpen = XMLHttpRequest.prototype.open;
var origSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.open = function () {
this._aksrtLoader = true;
return origOpen.apply(this, arguments);
};
XMLHttpRequest.prototype.send = function () {
if (this._aksrtLoader) {
start();
var self = this;
this.addEventListener('loadend', function () { done(); });
}
return origSend.apply(this, arguments);
};
}
function init() {
injectStyle();
createBar();
document.addEventListener('click', onLinkClick, true);
document.addEventListener('submit', onFormSubmit, true);
// Done on page load (handles bfcache)
window.addEventListener('pageshow', function (e) {
if (e.persisted) done();
});
window.addEventListener('load', done);
hookFetch();
hookXHR();
}
// Public API
window.AksrtLoader = {
start: start,
done: done
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();
-27
View File
@@ -1,27 +0,0 @@
/**
* AKSRT Frontend Shell
*
* All init modules have been extracted to assets/js/core/*.js.
* This file remains as the enqueue anchor (handle: aksrt-script) that
* other scripts depend on, and provides the AksrtFrontend fallback
* for edge cases where rehydrate.js is not loaded first.
*
* @package AKSRT
* @since 5.0.0
*/
(function () {
"use strict";
if (!window.AksrtFrontend) {
window.AksrtFrontend = {
register: function (name, fn) {
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", function () { fn(document, "init"); });
} else {
fn(document, "init");
}
},
rehydrate: function () {}
};
}
})();
+8 -2
View File
@@ -6,8 +6,11 @@
(function () {
'use strict';
var root = document.querySelector('[data-message-center]');
if (!root) return;
function init(scope) {
scope = scope || document;
var root = scope.nodeType === 1 && scope.matches('[data-message-center]') ? scope : scope.querySelector('[data-message-center]');
if (!root || root.dataset.aksrtMessagesBound === '1') return;
root.dataset.aksrtMessagesBound = '1';
var nonce = typeof aksrtData !== 'undefined' ? aksrtData.nonce : '';
var ajaxUrl = typeof aksrtData !== 'undefined' ? aksrtData.ajaxUrl : '/wp-admin/admin-ajax.php';
@@ -225,4 +228,7 @@
if (result.success && result.data) updateHeaderBadge(result.data.unread);
}).catch(function () {});
}, pollInterval);
}
window.AksrtFrontend.register('aksrt-messages', init);
})();
+6 -7
View File
@@ -307,8 +307,11 @@
};
// 自动初始化
function autoInit() {
document.querySelectorAll('[data-aksrt-mini-upload]').forEach(function (el) {
function autoInit(root) {
var containers = [];
if (root && root.nodeType === 1 && root.matches('[data-aksrt-mini-upload]')) containers.push(root);
Array.prototype.push.apply(containers, (root || document).querySelectorAll('[data-aksrt-mini-upload]'));
containers.forEach(function (el) {
if (el.dataset.miniUploadInit) return;
el.dataset.miniUploadInit = '1';
@@ -321,11 +324,7 @@
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', autoInit);
} else {
autoInit();
}
window.AksrtFrontend.register('aksrt-mini-upload', autoInit);
// 暴露到全局
window.AksrtMiniUpload = MiniUpload;
-1
View File
@@ -473,5 +473,4 @@
if (window.AksrtFrontend && typeof window.AksrtFrontend.register === "function") {
window.AksrtFrontend.register("aksrt-order-center", init);
}
init(document);
}());
+7 -9
View File
@@ -21,6 +21,7 @@
*/
function PageEdit(options) {
this.options = Object.assign({
form: null,
formSelector: 'form[data-aksrt-edit]',
titleSelector: 'input[name="title"], input[name="topic_title"]',
contentSelector: 'textarea[name="content"], textarea[name="topic_content"]',
@@ -29,7 +30,7 @@
draftKey: '',
}, options || {});
this.form = document.querySelector(this.options.formSelector);
this.form = this.options.form || document.querySelector(this.options.formSelector);
if (!this.form) return;
this.autoSaveTimer = null;
@@ -189,18 +190,15 @@
};
// 自动初始化
function autoInit() {
var form = document.querySelector('form[data-aksrt-edit]');
function autoInit(root) {
var form = root && root.nodeType === 1 && root.matches('form[data-aksrt-edit]')
? root : (root || document).querySelector('form[data-aksrt-edit]');
if (form) {
new PageEdit();
new PageEdit({ form: form });
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', autoInit);
} else {
autoInit();
}
window.AksrtFrontend.register('aksrt-page-edit', autoInit);
window.AksrtPageEdit = PageEdit;
})();
+24 -20
View File
@@ -28,7 +28,10 @@
searchQuery: '',
ajaxInFlight: null,
init: function () {
init: function (root) {
this.root = root || document;
if (this.root.__aksrtPageNavInitialized) return;
this.root.__aksrtPageNavInitialized = true;
this.initTocHighlight();
this.initSmoothScroll();
this.initDocSearch();
@@ -40,7 +43,8 @@
* TOC 高亮(文档阅读页)
* ============================================================ */
initTocHighlight: function () {
var toc = document.querySelector('.aksrt-doc-toc');
var toc = this.root.querySelector('.aksrt-doc-toc');
if (this.root.nodeType === 1 && this.root.matches('.aksrt-doc-toc')) toc = this.root;
if (!toc) return;
this.tocItems = Array.from(toc.querySelectorAll('.aksrt-doc-toc__item a'));
@@ -92,7 +96,9 @@
* 平滑滚动
* ============================================================ */
initSmoothScroll: function () {
document.addEventListener('click', function (e) {
if (this.root.__aksrtPageNavSmoothBound) return;
this.root.__aksrtPageNavSmoothBound = true;
this.root.addEventListener('click', function (e) {
var link = e.target.closest('a[href^="#"]');
if (!link) return;
@@ -113,11 +119,11 @@
* 文档搜索(AJAX 接管)
* ============================================================ */
initDocSearch: function () {
var searchInput = document.querySelector('.aksrt-doc-search__input');
var searchInput = this.root.querySelector('.aksrt-doc-search__input');
if (!searchInput) return;
var resultsContainer = document.querySelector('.aksrt-doc-search__results');
var takeover = document.querySelector('.aksrt-doc-takeover');
var resultsContainer = this.root.querySelector('.aksrt-doc-search__results');
var takeover = this.root.querySelector('.aksrt-doc-takeover');
var self = this;
var debounceTimer = null;
@@ -206,7 +212,7 @@
resultsContainer.innerHTML = '';
}
// 显示所有卡片
var cards = document.querySelectorAll('.aksrt-doc-index-card');
var cards = this.root.querySelectorAll('.aksrt-doc-index-card');
cards.forEach(function (card) { card.style.display = ''; });
},
@@ -231,7 +237,7 @@
* 分类切换 — AJAX 加载 + 分页
* ============================================================ */
initCategoryChips: function () {
var toolbar = document.querySelector('.aksrt-doc-toolbar');
var toolbar = this.root.querySelector('.aksrt-doc-toolbar');
if (!toolbar) return;
var chips = toolbar.querySelectorAll('.aksrt-doc-toolbar__chip[data-cat-id]');
@@ -260,7 +266,7 @@
}
var self = this;
var grid = document.querySelector('.aksrt-doc-grid');
var grid = this.root.querySelector('.aksrt-doc-grid');
if (!grid) return;
// 显示加载状态
@@ -305,7 +311,7 @@
},
updateMetaCount: function (total) {
var meta = document.querySelector('.aksrt-doc-toolbar__meta');
var meta = this.root.querySelector('.aksrt-doc-toolbar__meta');
if (meta) {
meta.textContent = total + ' 篇文档';
}
@@ -316,7 +322,7 @@
* ============================================================ */
initPagination: function () {
var self = this;
var paginationContainer = document.querySelector('.aksrt-doc-pagination');
var paginationContainer = this.root.querySelector('.aksrt-doc-pagination');
if (!paginationContainer) return;
paginationContainer.addEventListener('click', function (e) {
@@ -331,7 +337,7 @@
self.loadCategoryDocs(self.activeCategory, page);
// 滚动到顶部
var grid = document.querySelector('.aksrt-doc-grid');
var grid = self.root.querySelector('.aksrt-doc-grid');
if (grid) {
grid.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
@@ -342,7 +348,7 @@
this.totalPages = totalPages;
this.currentPage = currentPage;
var container = document.querySelector('.aksrt-doc-pagination');
var container = this.root.querySelector('.aksrt-doc-pagination');
if (!container) return;
if (totalPages <= 1) {
@@ -394,7 +400,7 @@
},
filterDocItems: function (query) {
var cards = document.querySelectorAll('.aksrt-doc-index-card');
var cards = this.root.querySelectorAll('.aksrt-doc-index-card');
if (cards.length > 0) {
cards.forEach(function (card) {
var title = card.querySelector('.aksrt-doc-index-card__title');
@@ -408,7 +414,7 @@
});
}
var sidebarItems = document.querySelectorAll('.aksrt-doc-sidebar__item');
var sidebarItems = this.root.querySelectorAll('.aksrt-doc-sidebar__item');
if (sidebarItems.length > 0) {
sidebarItems.forEach(function (item) {
var link = item.querySelector('.aksrt-doc-sidebar__link');
@@ -446,9 +452,7 @@
}
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function () { PAGE_NAVS.init(); });
} else {
PAGE_NAVS.init();
}
window.AksrtFrontend.register('aksrt-page-navs', function (root) {
PAGE_NAVS.init(root);
});
})();
+22 -13
View File
@@ -10,9 +10,15 @@
(function () {
'use strict';
function initContentExpand() {
function queryAll(root, selector) {
var nodes = Array.prototype.slice.call((root || document).querySelectorAll(selector));
if (root && root.nodeType === 1 && root.matches(selector)) nodes.unshift(root);
return nodes;
}
function initContentExpand(root) {
// legacy-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) {
queryAll(root, '.wp-posts-content.limit-height, .limit-height[data-nav]').forEach(function (content) {
if (content.dataset.aksrtExpandBound === '1') return;
content.dataset.aksrtExpandBound = '1';
@@ -58,8 +64,13 @@
wrap.remove();
});
});
}
// Compatibility: old external expand buttons.
var expandDelegateBound = false;
function bindExpandDelegate() {
if (expandDelegateBound) return;
expandDelegateBound = true;
document.addEventListener('click', function (event) {
var open = event.target.closest && event.target.closest('.read-more-open');
if (!open) return;
@@ -73,8 +84,8 @@
});
}
function initFlashQueryCleanup() {
document.querySelectorAll('[data-aksrt-flash-query]').forEach(function (node) {
function initFlashQueryCleanup(root) {
queryAll(root, '[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;
@@ -86,14 +97,12 @@
});
}
function init() {
initContentExpand();
initFlashQueryCleanup();
function init(root) {
root = root || document;
bindExpandDelegate();
initContentExpand(root);
initFlashQueryCleanup(root);
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
window.AksrtFrontend.register('aksrt-page-template', init);
})();
+1 -5
View File
@@ -567,9 +567,5 @@
document.addEventListener("click", onDocClick, true);
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", bindOnce, { once: true });
} else {
bindOnce();
}
window.AksrtFrontend.register("aksrt-pay-vip", bindOnce);
})();
+6 -4
View File
@@ -271,7 +271,11 @@
return Promise.resolve({ mode: 'window' });
}
var genericShareBound = false;
function bindGenericShareButtons() {
if (genericShareBound) return;
genericShareBound = true;
document.addEventListener('click', function (event) {
var node = event.target.closest('[data-share-platform]');
if (!node || node.closest('#share-dropdown')) return;
@@ -299,9 +303,7 @@
bindGenericShareButtons();
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
window.AksrtFrontend.register('aksrt-post-share', function () {
init();
}
});
})();
+16 -16
View File
@@ -37,7 +37,11 @@
PosterShare.prototype.init = function () {
var self = this;
document.querySelectorAll(this.options.triggerSelector).forEach(function (btn) {
var scope = this.options.root || document;
var triggers = [];
if (scope.nodeType === 1 && scope.matches(this.options.triggerSelector)) triggers.push(scope);
Array.prototype.push.apply(triggers, scope.querySelectorAll(this.options.triggerSelector));
triggers.forEach(function (btn) {
btn.addEventListener('click', function (e) {
e.preventDefault();
@@ -360,25 +364,21 @@
};
// 自动初始化
function autoInit() {
document.querySelectorAll('[data-aksrt-poster]').forEach(function (el) {
if (el.dataset.posterInit) return;
function autoInit(root) {
var triggers = [];
if (root && root.nodeType === 1 && root.matches('[data-aksrt-poster]')) triggers.push(root);
Array.prototype.push.apply(triggers, (root || document).querySelectorAll('[data-aksrt-poster]'));
if (!triggers.length) return;
var pending = triggers.filter(function (el) { return el.dataset.posterInit !== '1'; });
if (!pending.length) return;
var instance = new PosterShare({ root: root || document, triggerSelector: '[data-aksrt-poster]' });
pending.forEach(function (el) {
el.dataset.posterInit = '1';
var config = {};
try {
config = JSON.parse(el.dataset.aksrtPoster || '{}');
} catch (e) {}
new PosterShare({ triggerSelector: '[data-aksrt-poster]' });
el._aksrtPosterShare = instance;
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', autoInit);
} else {
autoInit();
}
window.AksrtFrontend.register('aksrt-poster-share', autoInit);
/**
* Generate a poster directly from a unified share payload, without binding
+26 -23
View File
@@ -8,11 +8,14 @@
'use strict';
function qs(sel, root) {
if (root && root.nodeType === 1 && root.matches(sel)) return root;
return (root || document).querySelector(sel);
}
function qsa(sel, root) {
return Array.prototype.slice.call((root || document).querySelectorAll(sel));
var nodes = Array.prototype.slice.call((root || document).querySelectorAll(sel));
if (root && root.nodeType === 1 && root.matches(sel)) nodes.unshift(root);
return nodes;
}
function ajaxUrl() {
@@ -21,10 +24,13 @@
return '/wp-admin/admin-ajax.php';
}
function initModal() {
var modal = qs('#post-navs-sz');
function initModal(root) {
var modal = qs('#post-navs-sz', root);
if (!modal) return;
if (modal.dataset.aksrtPostsNavModalBound === '1') return;
modal.dataset.aksrtPostsNavModalBound = '1';
function openModal(e) {
if (e) e.preventDefault();
modal.classList.add('is-open', 'show');
@@ -37,11 +43,11 @@
modal.setAttribute('aria-hidden', 'true');
}
qsa('[data-toggle="modal"][data-target="#post-navs-sz"], a[href="#post-navs-sz"]').forEach(function (el) {
qsa('[data-toggle="modal"][data-target="#post-navs-sz"], a[href="#post-navs-sz"]', root).forEach(function (el) {
el.addEventListener('click', openModal);
});
// Title [设置] uses data-target.
qsa('[data-target="#post-navs-sz"]').forEach(function (el) {
qsa('[data-target="#post-navs-sz"]', root).forEach(function (el) {
el.addEventListener('click', openModal);
});
qsa('[data-dismiss="modal"]', modal).forEach(function (btn) {
@@ -55,9 +61,9 @@
});
}
function initDragSort() {
var left = qs('#cat-sortable');
var right = qs('#cat-sortable-ok');
function initDragSort(root) {
var left = qs('#cat-sortable', root);
var right = qs('#cat-sortable-ok', root);
if (!left || !right) return;
var dragEl = null;
@@ -123,8 +129,8 @@
}
}
function initSave() {
var form = qs('#aksrt-posts-navs-settings');
function initSave(root) {
var form = qs('#aksrt-posts-navs-settings', root);
if (!form) return;
form.addEventListener('submit', function (e) {
@@ -179,9 +185,9 @@
* Build simple TOC into .posts-nav-box if section-navs hasn't already.
* Uses category h2 headings inside .posts-navs.
*/
function initFallbackToc() {
var box = qs('.posts-nav-box');
var root = qs('.posts-navs[data-nav]');
function initFallbackToc(scope) {
var box = qs('.posts-nav-box', scope);
var root = qs('.posts-navs[data-nav]', scope);
if (!box || !root) return;
if (box.querySelector('.posts-nav-lists, .aksrt-section-nav, .toc-list')) return;
@@ -230,17 +236,14 @@
highlight();
}
function init() {
initModal();
initDragSort();
initSave();
function init(root) {
root = root || document;
initModal(root);
initDragSort(root);
initSave(root);
// Defer so section-navs.js can own TOC first.
window.setTimeout(initFallbackToc, 50);
window.setTimeout(function () { initFallbackToc(root); }, 50);
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
window.AksrtFrontend.register('aksrt-posts-navs-page', init);
})();
+2 -4
View File
@@ -218,9 +218,7 @@
loadEnlighterJS(initEnlighter);
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
window.AksrtFrontend.register('aksrt-precode', function () {
init();
}
});
})();
+45 -17
View File
@@ -6,8 +6,9 @@
* to initialize or re-initialize them on a given root element.
*
* Usage:
* AksrtFrontend.register('name', initFn); // Register a component
* AksrtFrontend.rehydrate(root, 'init'); // Initialize all components
* AksrtFrontend.register('name', initFn); // Register a component
* AksrtFrontend.boot(document); // One-time initial page load
* AksrtFrontend.rehydrate(root, 'ajax'); // Initialize dynamic content
*
* @package AKSRT
* @since 5.0.0
@@ -16,7 +17,25 @@
'use strict';
var _registry = [];
var _initialized = [];
var _booted = false;
var _bootRoot = null;
function invoke(entry, root, reason) {
try {
entry.initFn(root, reason);
} catch (err) {
console.error('[AKSRT Rehydrate] Error initializing "' + entry.name + '":', err);
}
}
function dispatch(root, reason, eventName) {
try {
root.dispatchEvent(new CustomEvent(eventName, {
bubbles: true,
detail: { reason: reason }
}));
} catch (e) { /* IE fallback */ }
}
window.AksrtFrontend = {
@@ -32,10 +51,26 @@
for (var i = 0; i < _registry.length; i++) {
if (_registry[i].name === name) {
_registry[i].initFn = initFn;
if (_booted) invoke(_registry[i], _bootRoot || document, 'init');
return;
}
}
_registry.push({ name: name, initFn: initFn });
var entry = { name: name, initFn: initFn };
_registry.push(entry);
if (_booted) invoke(entry, _bootRoot || document, 'init');
},
/**
* Run the one-time initial page boot.
*
* @param {Element|Document} root The document root to initialize
*/
boot: function (root) {
if (_booted) return;
_booted = true;
_bootRoot = root || document;
this.rehydrate(_bootRoot, 'init');
dispatch(_bootRoot, 'init', 'aksrt:ready');
},
/**
@@ -53,21 +88,10 @@
reason = reason || 'init';
for (var i = 0; i < _registry.length; i++) {
var entry = _registry[i];
try {
entry.initFn(root, reason);
} catch (err) {
console.error('[AKSRT Rehydrate] Error initializing "' + entry.name + '":', err);
}
invoke(_registry[i], root, reason);
}
// Dispatch event so external scripts can hook in
try {
root.dispatchEvent(new CustomEvent('aksrt:rehydrated', {
bubbles: true,
detail: { reason: reason }
}));
} catch (e) { /* IE fallback */ }
dispatch(root, reason, 'aksrt:rehydrated');
},
/**
@@ -75,6 +99,10 @@
*/
getRegistered: function () {
return _registry.map(function (r) { return r.name; });
},
isBooted: function () {
return _booted;
}
};
+4 -5
View File
@@ -141,6 +141,8 @@
}
function initReportButtons() {
if (document.documentElement.dataset.aksrtReportInitialized === '1') return;
document.documentElement.dataset.aksrtReportInitialized = '1';
document.addEventListener('click', function (e) {
var btn = e.target.closest('[data-aksrt-report]');
if (!btn) return;
@@ -157,10 +159,7 @@
});
}
// Auto-init on DOMContentLoaded
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initReportButtons);
} else {
initReportButtons();
if (window.AksrtFrontend && typeof window.AksrtFrontend.register === 'function') {
window.AksrtFrontend.register('aksrt-report', initReportButtons);
}
})();
+4 -5
View File
@@ -8,7 +8,10 @@
var cfg = window.aksrtData || {};
function initReward() {
function initReward(root) {
if (root && root.nodeType === 1 && !root.matches('[data-aksrt-reward-root], body, html')) return;
if (document.documentElement.dataset.aksrtRewardInitialized === '1') return;
document.documentElement.dataset.aksrtRewardInitialized = '1';
var activeTrigger = null;
function operationKey(modal) {
@@ -125,9 +128,5 @@
if (window.AksrtFrontend && typeof window.AksrtFrontend.register === 'function') {
window.AksrtFrontend.register('aksrt-reward', initReward);
} else if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initReward);
} else {
initReward();
}
})();
+41 -58
View File
@@ -41,9 +41,11 @@
}
/* ==================== Dashboard 导航 ==================== */
function initDashboardNavigation() {
var tabContainer = document.querySelector('.uc-mobile-tabs');
if (!tabContainer) return;
function initDashboardNavigation() {
if (document.documentElement.dataset.aksrtUserCenterNavigationInitialized === 'true') return;
var tabContainer = document.querySelector('.uc-mobile-tabs');
if (!tabContainer) return;
document.documentElement.dataset.aksrtUserCenterNavigationInitialized = 'true';
var tabs = tabContainer.querySelectorAll('[data-tab]');
var sidebarBtns = document.querySelectorAll('.uc-sidebar [data-tab]');
@@ -322,22 +324,18 @@
});
}
if (window.AksrtFrontend && typeof window.AksrtFrontend.register === 'function') {
window.AksrtFrontend.register('aksrt-profile-form', function(root) {
initProfileForm(root);
});
}
function initAuthForm() {
var root = document.querySelector('[data-identity-root]');
if (root && window.AKSRTUserCenterAuth && typeof window.AKSRTUserCenterAuth.init === 'function') {
window.AKSRTUserCenterAuth.init(root);
function initAuthForm(root) {
root = root || document;
var identityRoot = root.matches && root.matches('[data-identity-root]') ? root : root.querySelector('[data-identity-root]');
if (identityRoot && window.AKSRTUserCenterAuth && typeof window.AKSRTUserCenterAuth.init === 'function') {
window.AKSRTUserCenterAuth.init(identityRoot);
}
}
}
/* ==================== 列表内取消收藏 ==================== */
function initUnfavorite() {
var list = document.querySelector('.profile-list[data-list="favorites"]');
function initUnfavorite(root) {
root = root || document;
var list = root.matches && root.matches('.profile-list[data-list="favorites"]') ? root : root.querySelector('.profile-list[data-list="favorites"]');
if (!list) return;
list.addEventListener('click', function(e) {
@@ -395,9 +393,9 @@
});
}
function initPostDeletion() {
if (document.documentElement.dataset.aksrtPostDeletionBound === 'true') return;
document.documentElement.dataset.aksrtPostDeletionBound = 'true';
function initPostDeletion(root) {
if (document.documentElement.dataset.aksrtPostDeletionBound === 'true') return;
document.documentElement.dataset.aksrtPostDeletionBound = 'true';
document.addEventListener('click', function(e) {
var btn = e.target && e.target.closest ? e.target.closest('[data-action="delete-post"]') : null;
if (!btn || btn.disabled || !confirm('确定删除这篇文章?')) return;
@@ -423,12 +421,14 @@
}
/* ==================== 通知中心 ==================== */
function initNotifications() {
var list = document.getElementById('aksrt-notification-list');
var markAllBtn = document.getElementById('aksrt-mark-all-notifications-read');
var markSelectedBtn = document.getElementById('aksrt-mark-selected-notifications-read');
var deleteSelectedBtn = document.getElementById('aksrt-delete-selected-notifications');
if (!list) return;
function initNotifications(root) {
root = root || document;
var list = root.matches && root.matches('#aksrt-notification-list') ? root : root.querySelector('#aksrt-notification-list');
var markAllBtn = list && list.ownerDocument.getElementById('aksrt-mark-all-notifications-read');
var markSelectedBtn = list && list.ownerDocument.getElementById('aksrt-mark-selected-notifications-read');
var deleteSelectedBtn = list && list.ownerDocument.getElementById('aksrt-delete-selected-notifications');
if (!list || list.dataset.aksrtNotificationsInitialized === 'true') return;
list.dataset.aksrtNotificationsInitialized = 'true';
function markRead(notificationId, markAll) {
var body = new URLSearchParams();
@@ -1033,42 +1033,25 @@
}
}
if (window.AksrtFrontend && typeof window.AksrtFrontend.register === 'function') {
window.AksrtFrontend.register('aksrt-settings', function(root) {
initSettings(root);
initBindPhone(root);
});
window.AksrtFrontend.register('aksrt-notification-preferences', function(root) {
initNotificationPreferences(root);
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function() {
function initNavigationOnce() {
initDashboardNavigation();
initProfileForm();
initAuthForm();
initUnfavorite();
initPostDeletion();
initNotifications();
initNotificationPreferences();
initSettings();
initBindPhone();
initSettingsCallbackToast();
});
} else {
initDashboardNavigation();
initProfileForm();
initAuthForm();
initUnfavorite();
initPostDeletion();
initNotifications();
initNotificationPreferences();
initSettings();
initBindPhone();
initSettingsCallbackToast();
}
}
if (window.AksrtFrontend && typeof window.AksrtFrontend.register === 'function') {
window.AksrtFrontend.register('aksrt-user-center', function(root) {
initNavigationOnce();
initProfileForm(root);
initAuthForm(root);
initUnfavorite(root);
initNotifications(root);
initNotificationPreferences(root);
initSettings(root);
initBindPhone(root);
initSettingsCallbackToast();
});
}
// 绑定手机
function initBindPhone(root) {
-9
View File
@@ -59,17 +59,8 @@ tbquire.config({
'translate' : 'libs/translate.min',
'waterfall' : 'waterfall.min',
'enlighterjs' : 'enlighter/enlighterjs.min',
'section-navs' : 'section-navs.min',
'poster-share' : 'poster-share.min',
'comment' : 'comment.min',
'page-template' : 'page-template.min',
'page-edit' : 'page-edit.min',
'author' : 'author.min',
'page-navs' : 'page-navs.min',
'input-expand' : 'input-expand.min',
'mini-touch' : 'mini-touch.min',
'mini-upload' : 'mini-upload.min',
'editextend' : 'editextend.min',
'petite-vue' : 'libs/petite-vue.iife',
'svg-icon' : 'svg-icon',
+16 -39
View File
@@ -1872,7 +1872,7 @@ function post_ajax(_this, con, jcon, item, loader, pag, next, trigger, replace,
}
swiper_tab_AutoHeight($con);
auto_fun();
window.AksrtFrontend.rehydrate($con[0], 'ajax');
},
});
return !1;
@@ -1884,7 +1884,7 @@ _win.bd.on('click', '[remote-box]', function () {
if (remote) {
jQuery.post(remote, null, function (data) {
_this.html(data).removeAttr('remote-box');
auto_fun();
window.AksrtFrontend.rehydrate(_this[0], 'ajax');
_this.trigger('aksrt:remote-loaded');
});
}
@@ -2176,7 +2176,7 @@ _win.bd.on('show.bs.modal loaded.bs.modal', '.modal:not(.flex)', function () {
});
_win.bd.on('show.bs.modal loaded.bs.modal', '.modal', function () {
auto_fun();
window.AksrtFrontend.rehydrate(this, 'modal');
});
_win.modal_z_index = 1050;
@@ -2420,7 +2420,9 @@ function z_auto() {
}
}
window.auto_fun = debounce(z_auto_fun, 100);
window.auto_fun = debounce(function (root) {
window.AksrtFrontend.rehydrate(root && root.nodeType ? root : document, 'ajax');
}, 100);
function z_auto_fun() {
jQuery(document).trigger('auto_fun');
@@ -2433,9 +2435,6 @@ function z_auto_fun() {
//可复制
jQuery('.cloneable').cloneable();
//倒计时
jQuery('[data-countdown]').countdown();
auto_maxHeight();
//兼容性图片懒加载
jQuery('img[data-src]:not(.lazyload,.lazyloaded,.lazyloading,.swiper-lazy)').addClass('lazyload');
@@ -2446,13 +2445,6 @@ function z_auto_fun() {
});
*/
jQuery('.dropdown-code,.dropdown-image,.dropdown-quick-often').length && tbquire(['input-expand']);
/**上传图片 */
jQuery('[aksrtupload]').length && tbquire(['mini-upload']);
//海报分享
jQuery('[poster-share]').length && tbquire(['poster-share']); //海报分享
/* 提示工具*/
jQuery("[data-toggle='tooltip']").tooltip({
container: 'body',
@@ -3095,21 +3087,6 @@ _win.bd.on('input focus', 'textarea[autoHeight]', function () {
_win.bd.on('click', '.rewards', function () {
jQuery('#rewards-popover').modal('show');
});
//用户中心
_win.bd.hasClass('author') && tbquire(['author']);
//文章导航
_win.bd.hasClass('page-template-postsnavs') && _win.bd.hasClass('logged-admin') && tbquire(['page-navs']);
//前台编辑
jQuery('#modal_admin_set').length && tbquire(['page-edit']);
//评论
jQuery('#commentform,#postcomments').length && tbquire(['comment']);
//通用模板js文件
_win.bd.hasClass('page-template') && tbquire(['page-template']);
//微信分享
window.WeChatShareDate && tbquire(['weixin-share']);
//搜索关键词高亮
if (_win.bd.hasClass('search')) {
var val = jQuery('.search-desc-text .search-key').text();
@@ -3520,7 +3497,7 @@ jQuery.fn.AutoSearch = function () {
_this.removeClass(loading);
_remind.html(result.remind || '');
_icon.html(_icon_html);
auto_fun();
window.AksrtFrontend.rehydrate(_container[0], 'ajax');
},
'json'
);
@@ -3969,12 +3946,6 @@ function posts_limit_height() {
}
}
auto_fun();
thumb_dplayer(_wid > 640 ? '.posts-item .item-thumbnail,.forum-lists-cover' : '.posts-item,.forum-posts', '.video-thumb-box[video-url]');
//页面加载之后自动点击
jQuery('[load-click]').attr('no-scroll', true).click();
//图片延迟懒加载-ias自动加载
jQuery(document).on('lazybeforeunveil', function (e) {
var _this = jQuery(e.target);
@@ -4553,7 +4524,7 @@ _win.bd.on('click', '.customize-preview-widget-edit', function (e) {
});
//页面加载完毕之后加载的函数
jQuery(document).ready(function () {
function initLegacyDocumentReady() {
setTimeout(function () {
//页面加载完毕之后再延迟两秒加载的函数
@@ -4700,8 +4671,6 @@ jQuery(document).ready(function () {
});
/*文章目录*/
jQuery('[data-nav] h1,[data-nav] h2,[data-nav] h3,[data-nav] h4').length > 2 && tbquire(['section-navs']);
//手势控制
jQuery('[mini-touch]').each(function () {
var _this = jQuery(this);
@@ -4718,4 +4687,12 @@ jQuery(document).ready(function () {
},
});
});
}
window.AksrtFrontend.register('aksrt-legacy-main', function (root, reason) {
z_auto_fun();
if (reason !== 'init') return;
initLegacyDocumentReady();
thumb_dplayer(_wid > 640 ? '.posts-item .item-thumbnail,.forum-lists-cover' : '.posts-item,.forum-posts', '.video-thumb-box[video-url]');
jQuery('[load-click]').attr('no-scroll', true).click();
});
+1 -1
View File
File diff suppressed because one or more lines are too long
-46
View File
@@ -1,46 +0,0 @@
//文章导航
jQuery("button[evt='action']").on("click", function (t) {
t = t || window.event;
var a = t.target || t.srcElement,
e = jQuery(a),
n = e.parents("form"),
r = n.serializeObject(),
c = [];
return jQuery("#cat-sortable-ok .sortable-cat-item").each(function () {
c.push(jQuery(this).attr("data-id"));
}), r.navs_show_cat_id = c, save_userdata(r, aksrt__("save_success"), "reload"), !1;
});
function save_userdata(b, c, d) {
notyf(aksrt__("processing_wait"), "load", "", "user_ajax"),
c = c || aksrt__("done");
jQuery.ajax({
type: "POST",
url: _win.uri + '/action/post_navs.php',
data: b,
dataType: "json",
success: function (n) {
if (n.error) {
n.msg && notyf(n.msg, (n.error ? 'danger' : ""), "", "user_ajax");
} else {
notyf(n.msg || c, "", "", "user_ajax");
"reload" == d && location.reload();
}
}
});
}
jQuery(document).ready(function () {
jQuery("#cat-sortable").length && tbquire(["sortablejs"], function () {
var e = document.getElementById("cat-sortable"),
t = document.getElementById("cat-sortable-ok"),
a = {
group: "cat_shared",
multiDrag: !0,
chosenClass: "chosen",
fallbackClass: !0,
animation: 400
};
Sortable.create(e, a), Sortable.create(t, a);
});
});
-1
View File
@@ -1 +0,0 @@
function save_userdata(a,t,e){notyf(aksrt__("processing_wait"),"load","","user_ajax"),t=t||aksrt__("done"),jQuery.ajax({type:"POST",url:_win.uri+"/action/post_navs.php",data:a,dataType:"json",success:function(a){a.error?a.msg&&notyf(a.msg,a.error?"danger":"","","user_ajax"):(notyf(a.msg||t,"","","user_ajax"),"reload"==e&&location.reload())}})}jQuery("button[evt='action']").on("click",function(a){a=a||window.event;var t=a.target||a.srcElement,e=jQuery(t),o=e.parents("form"),r=o.serializeObject(),s=[];return jQuery("#cat-sortable-ok .sortable-cat-item").each(function(){s.push(jQuery(this).attr("data-id"))}),r.navs_show_cat_id=s,save_userdata(r,aksrt__("save_success"),"reload"),!1}),jQuery(document).ready(function(){jQuery("#cat-sortable").length&&tbquire(["sortablejs"],function(){var a=document.getElementById("cat-sortable"),t=document.getElementById("cat-sortable-ok"),e={group:"cat_shared",multiDrag:!0,chosenClass:"chosen",fallbackClass:!0,animation:400};Sortable.create(a,e),Sortable.create(t,e)})});
+27 -22
View File
@@ -40,8 +40,10 @@
return count >= MIN_HEADINGS ? html : '';
}
function fillBoxes(listsHtml) {
document.querySelectorAll(NAVBOX).forEach(function (box) {
function fillBoxes(listsHtml, scope) {
var boxes = Array.prototype.slice.call(scope.querySelectorAll(NAVBOX));
if (scope.nodeType === 1 && scope.matches(NAVBOX)) boxes.unshift(scope);
boxes.forEach(function (box) {
var existing = box.querySelector('.' + NAV_CLASS);
if (existing) {
existing.innerHTML = listsHtml;
@@ -75,7 +77,13 @@
window.scrollTo({ top: top, behavior: 'smooth' });
}
var clicksBound = false;
var scrollspyBound = false;
var autoHashHandled = false;
function bindClicks() {
if (clicksBound) return;
clicksBound = true;
document.addEventListener('click', function (e) {
var a = e.target && e.target.closest ? e.target.closest('.' + NAV_CLASS + ' a[href^="#"]') : null;
if (!a) return;
@@ -87,9 +95,11 @@
});
}
function scrollspy() {
var links = document.querySelectorAll('.' + NAV_CLASS + ' a[href^="#"]');
function scrollspy(scope) {
if (scrollspyBound) return;
var links = scope.querySelectorAll('.' + NAV_CLASS + ' a[href^="#"]');
if (!links.length) return;
scrollspyBound = true;
var map = [];
links.forEach(function (a) {
var id = a.getAttribute('href').slice(1);
@@ -111,37 +121,32 @@
}
function autoHash() {
if (window.location.hash) {
setTimeout(function () {
smoothTo(window.location.hash);
}, 40);
}
if (autoHashHandled || !window.location.hash) return;
autoHashHandled = true;
setTimeout(function () {
smoothTo(window.location.hash);
}, 40);
}
function init() {
function init(scope) {
scope = scope || document;
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');
var root = scope.nodeType === 1 && scope.matches('[data-nav], .article-content, .entry-content, main.article')
? scope
: scope.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);
fillBoxes(listsHtml, document);
bindClicks();
scrollspy();
scrollspy(document);
autoHash();
}
if (window.AksrtFrontend && typeof window.AksrtFrontend.register === 'function') {
window.AksrtFrontend.register('aksrt-section-navs', function () {
init();
});
} else if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
window.AksrtFrontend.register('aksrt-section-navs', init);
})();
+17 -12
View File
@@ -29,8 +29,11 @@
});
}
function initSignin() {
var buttons = Array.prototype.slice.call(document.querySelectorAll('[data-signin-btn]'));
function initSignin(scope) {
scope = scope || document;
var buttons = [];
if (scope.nodeType === 1 && scope.matches('[data-signin-btn]')) buttons.push(scope);
if (scope.querySelectorAll) scope.querySelectorAll('[data-signin-btn]').forEach(function (button) { buttons.push(button); });
var freshButtons = buttons.filter(function (button) {
return button.dataset.aksrtSigninInitialized !== '1';
});
@@ -40,12 +43,19 @@
button.dataset.aksrtSigninInitialized = '1';
});
function elements(selector) {
var items = [];
if (scope.nodeType === 1 && scope.matches(selector)) items.push(scope);
if (scope.querySelectorAll) scope.querySelectorAll(selector).forEach(function (item) { items.push(item); });
return items;
}
function statuses() {
return document.querySelectorAll('[data-signin-status]');
return elements('[data-signin-status]');
}
function currentButtons() {
return document.querySelectorAll('[data-signin-btn]');
return elements('[data-signin-btn]');
}
function setStatus(text) {
@@ -98,7 +108,8 @@
}
function captchaMount() {
return document.querySelector('[data-signin-captcha]');
if (scope.nodeType === 1 && scope.matches('[data-signin-captcha]')) return scope;
return scope.querySelector ? scope.querySelector('[data-signin-captcha]') : null;
}
function doSignin(captchaPayload) {
@@ -115,7 +126,7 @@
}
notyf(result.json.message || '签到成功', 'success', 5, 'aksrt-balance-signin-toast');
document.querySelectorAll('[data-credits-value]').forEach(function (element) {
elements('[data-credits-value]').forEach(function (element) {
element.textContent = Number(result.json.balance || 0).toLocaleString();
});
setButtonState('done');
@@ -149,12 +160,6 @@
refresh();
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initSignin);
} else {
initSignin();
}
if (window.AksrtFrontend && typeof window.AksrtFrontend.register === 'function') {
window.AksrtFrontend.register('signin', initSignin);
}
+6 -2
View File
@@ -10,8 +10,11 @@
(function () {
'use strict';
var el = document.getElementById('aksrt-site-notice');
if (!el) return;
window.AksrtFrontend.register('aksrt-site-notice', function (root) {
root = root || document;
var el = root.nodeType === 1 && root.matches('#aksrt-site-notice') ? root : root.querySelector('#aksrt-site-notice');
if (!el || el.dataset.aksrtNoticeBound === '1') return;
el.dataset.aksrtNoticeBound = '1';
// 弹窗周期(小时),0=永不过期
var expiresHours = parseInt(el.dataset.expires || '24', 10) || 0;
@@ -88,4 +91,5 @@
// Delay slightly so it doesn't flash on fast navigations
setTimeout(show, 500);
}
});
})();
+8 -2
View File
@@ -19,7 +19,10 @@
if (typeof window.notyf === 'function') window.notyf(message, type);
}
document.addEventListener('click', function (event) {
function bindOnce() {
if (document.__aksrtUserBadgeActionsBound) return;
document.__aksrtUserBadgeActionsBound = true;
document.addEventListener('click', function (event) {
var button = event.target.closest('[data-aksrt-badge-action]');
if (!button || button.classList.contains('is-loading')) return;
@@ -56,5 +59,8 @@
button.removeAttribute('aria-busy');
notice(error.message || '网络错误', 'danger');
});
});
});
}
window.AksrtFrontend.register('aksrt-user-badge-actions', bindOnce);
})(window, document);
+14 -11
View File
@@ -219,7 +219,10 @@
};
// ── 剧集切换按钮事件委托 ──
document.addEventListener('click', function (e) {
function bindEpisodeSwitch() {
if (document.__aksrtVideoEpisodeBound) return;
document.__aksrtVideoEpisodeBound = true;
document.addEventListener('click', function (e) {
var switchBtn = e.target.closest('.switch-video, .switch-iframe');
if (!switchBtn) return;
@@ -256,24 +259,24 @@
});
switchBtn.classList.add('is-active');
switchBtn.classList.add('active');
});
});
}
// ── Public API ──
window.AksrtVideoPlayer = AksrtVideoPlayer;
// ── Auto-init ──
function init() {
function init(root) {
root = root || document;
injectStyle();
document.querySelectorAll('[data-aksrt-video]').forEach(function (el) {
bindEpisodeSwitch();
var elements = [];
if (root && root.nodeType === 1 && root.matches('[data-aksrt-video]')) elements.push(root);
Array.prototype.push.apply(elements, root.querySelectorAll('[data-aksrt-video]'));
elements.forEach(function (el) {
new AksrtVideoPlayer(el);
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
window.AksrtFrontend.register('aksrt-video-player', init);
})();
+19 -11
View File
@@ -154,24 +154,32 @@
});
}
function autoInit() {
document.querySelectorAll('[data-aksrt-waterfall]').forEach(function (el) {
function autoInit(root) {
var elements = [];
if (root && root.nodeType === 1 && root.matches('[data-aksrt-waterfall]')) elements.push(root);
Array.prototype.push.apply(elements, (root || document).querySelectorAll('[data-aksrt-waterfall]'));
elements.forEach(function (el) {
if (el._aksrtWaterfall) return;
var cols = parseInt(el.dataset.aksrtWaterfallColumns) || 0;
var gap = parseInt(el.dataset.aksrtWaterfallGap) || 16;
waterfallInstances.push(new Waterfall(el, { columns: cols, gap: gap }));
el._aksrtWaterfall = new Waterfall(el, { columns: cols, gap: gap });
waterfallInstances.push(el._aksrtWaterfall);
});
}
document.addEventListener('post_ajax.ed', relayoutAll);
document.addEventListener('aksrt:posts:rendered', relayoutAll);
document.addEventListener('lazyloaded', relayoutAll, true);
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', autoInit);
} else {
autoInit();
function bindGlobalEvents() {
if (document.__aksrtWaterfallEventsBound) return;
document.__aksrtWaterfallEventsBound = true;
document.addEventListener('post_ajax.ed', relayoutAll);
document.addEventListener('aksrt:posts:rendered', relayoutAll);
document.addEventListener('lazyloaded', relayoutAll, true);
}
window.AksrtFrontend.register('aksrt-waterfall', function (root) {
bindGlobalEvents();
autoInit(root);
});
// Export to global
window.AksrtWaterfall = Waterfall;
window.AksrtInfiniteScroll = InfiniteScroll;
+5 -2
View File
@@ -249,7 +249,10 @@
});
}
document.addEventListener('DOMContentLoaded', function () {
document.querySelectorAll('[data-aksrt-yiyan]').forEach(initYiyan);
window.AksrtFrontend.register('aksrt-yiyan', function (root) {
var elements = [];
if (root && root.nodeType === 1 && root.matches('[data-aksrt-yiyan]')) elements.push(root);
Array.prototype.push.apply(elements, (root || document).querySelectorAll('[data-aksrt-yiyan]'));
elements.forEach(initYiyan);
});
})();