diff --git a/.gitignore b/.gitignore
index be217e55..37c30a2d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -45,6 +45,10 @@
!/tests/widget-system/front-submit-editor-contract.test.cjs
!/tests/widget-system/comment-smilies-removal-contract.test.cjs
!/tests/widget-system/lightbox-contract.test.cjs
+!/tests/widget-system/homepage-dom-contract.test.cjs
+!/tests/widget-system/rehydrate-runtime-contract.test.cjs
+!/tests/widget-system/global-dom-init-contract.test.cjs
+!/tests/widget-system/public-bundle-parity-contract.test.cjs
!/tests/widget-system/comment-children-list-reset-contract.test.cjs
!/tests/widget-system/pay-card-contract.test.cjs
!/tests/widget-system/circular-button-icon-margin-contract.test.cjs
diff --git a/assets/js/aksrt-runtime.js b/assets/js/aksrt-runtime.js
index 44f02898..60fc172d 100644
--- a/assets/js/aksrt-runtime.js
+++ b/assets/js/aksrt-runtime.js
@@ -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') {
diff --git a/assets/js/auth.js b/assets/js/auth.js
index f02f864f..71974db6 100644
--- a/assets/js/auth.js
+++ b/assets/js/auth.js
@@ -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();
+ });
+ }
}());
diff --git a/assets/js/author.js b/assets/js/author.js
index ef37a4b1..e10c3b09 100644
--- a/assets/js/author.js
+++ b/assets/js/author.js
@@ -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);
}
})();
diff --git a/assets/js/ban-appeal-page.js b/assets/js/ban-appeal-page.js
index 74c750e8..157c24b2 100644
--- a/assets/js/ban-appeal-page.js
+++ b/assets/js/ban-appeal-page.js
@@ -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);
})();
diff --git a/assets/js/build/public.js b/assets/js/build/public.js
index f2f13018..eb2dacd3 100644
--- a/assets/js/build/public.js
+++ b/assets/js/build/public.js
@@ -65,17 +65,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',
@@ -133,8 +124,9 @@ tbquire.config({
* 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
@@ -143,7 +135,25 @@ tbquire.config({
'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 = {
@@ -159,10 +169,26 @@ tbquire.config({
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');
},
/**
@@ -180,21 +206,10 @@ tbquire.config({
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');
},
/**
@@ -202,6 +217,10 @@ tbquire.config({
*/
getRegistered: function () {
return _registry.map(function (r) { return r.name; });
+ },
+
+ isBooted: function () {
+ return _booted;
}
};
@@ -543,64 +562,7 @@ tbquire.config({
});
}, 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
// ══════════════════════════════════════════════════════════════
@@ -807,13 +769,7 @@ tbquire.config({
// §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';
@@ -831,8 +787,9 @@ tbquire.config({
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';
@@ -846,6 +803,20 @@ tbquire.config({
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);
+ }
};
// ══════════════════════════════════════════════════════════════
@@ -864,7 +835,7 @@ tbquire.config({
// ── DOMContentLoaded ──
function initRuntime() {
- aksrt.autoFun(document);
+ aksrt.autoFun(document, 'init');
}
if (document.readyState === 'loading') {
@@ -2948,19 +2919,6 @@ tbquire.config({
}
}
- 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;
@@ -2976,25 +2934,50 @@ tbquire.config({
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;
})();
;
@@ -4241,6 +4224,18 @@ tbquire.config({
(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;
@@ -4269,26 +4264,15 @@ tbquire.config({
}
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) {
@@ -4319,25 +4303,17 @@ tbquire.config({
});
}
- 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");
@@ -4347,33 +4323,32 @@ tbquire.config({
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;
@@ -4394,7 +4369,7 @@ tbquire.config({
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);
@@ -4402,7 +4377,7 @@ tbquire.config({
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",
@@ -4425,24 +4400,21 @@ tbquire.config({
});
});
- // 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);
+ });
})();
;
@@ -4493,7 +4465,11 @@ tbquire.config({
}
}
- 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;
@@ -4541,11 +4517,7 @@ tbquire.config({
});
}
- if (document.readyState === 'loading') {
- document.addEventListener('DOMContentLoaded', initFollowButtons);
- } else {
- initFollowButtons();
- }
+ window.AksrtFrontend.register('aksrt-follow', initFollowButtons);
})();
;
@@ -4573,6 +4545,8 @@ tbquire.config({
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]';
@@ -5048,7 +5022,9 @@ tbquire.config({
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;
@@ -5079,7 +5055,9 @@ tbquire.config({
// 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() {
@@ -5099,9 +5077,9 @@ tbquire.config({
}, { passive: true });
}
- document.addEventListener('DOMContentLoaded', function () {
- initLightbox();
- initScrollDirection();
+ window.AksrtFrontend.register('aksrt-enhancements', function (root, reason) {
+ initLightbox(root, reason);
+ initScrollDirection(root, reason);
});
})();
;
@@ -5118,11 +5096,27 @@ tbquire.config({
(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';
@@ -5167,232 +5161,186 @@ tbquire.config({
});
}
- /* ============================================================
- * 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 = '
';
-
- 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 += '
' +
- '' + d.getDate() + '' +
- '
';
- }
-
- html += '
';
- 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 = '
';
+ 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 += '
' + d.getDate() + '
';
+ }
+ calendar.innerHTML = html + '
';
+ });
}
- /* ============================================================
- * 初始化入口
- * ============================================================ */
- 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,
};
-
})();
;
@@ -5498,7 +5446,8 @@ tbquire.config({
}
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) {
@@ -5526,8 +5475,10 @@ tbquire.config({
}
}
- 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
@@ -5538,11 +5489,7 @@ tbquire.config({
init: init
};
- if (document.readyState === 'loading') {
- document.addEventListener('DOMContentLoaded', init);
- } else {
- init();
- }
+ window.AksrtFrontend.register('aksrt-color-extract', init);
})();
;
@@ -5559,108 +5506,101 @@ tbquire.config({
'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 触发
- * 用法:0
- * ============================================================ */
- 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. 倒计时组件
- * 用法:--:--:--
- * ============================================================ */
- 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)
- * 用法:
",n.html(y_nr)}})}jQuery(".yiyan").each(function(){yiyan_nr(jQuery(this))}),setInterval(function(){jQuery(".yiyan").each(function(){yiyan_nr(jQuery(this))})},3e4),jQuery(".yiyan").on("click",function(){yiyan_nr(jQuery(this))}),jQuery("[mini-touch]").each(function(){var _this=jQuery(this),fx=_this.attr("touch-direction");_this.minitouch({direction:fx,onEnd:function(e){_this.attr("mini-touch")==="mobile-nav"?jQuery("body").removeClass("mobile-navbar-show"):e.removeClass("show")}})})}window.AksrtFrontend.register("aksrt-legacy-main",function(root,reason){z_auto_fun(),reason==="init"&&(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",!0).click())});
;
/* source: assets/js/captcha-front.js */
@@ -5855,8 +5779,11 @@ jQuery.cookie=function(e,a,t){if(a===void 0){var r=null;if(document.cookie&&docu
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;
@@ -6279,15 +6206,7 @@ jQuery.cookie=function(e,a,t){if(a===void 0){var r=null;if(document.cookie&&docu
}
}
- 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);
})();
;
diff --git a/assets/js/captcha-front.js b/assets/js/captcha-front.js
index 646b3d82..eed03c3c 100644
--- a/assets/js/captcha-front.js
+++ b/assets/js/captcha-front.js
@@ -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);
})();
diff --git a/assets/js/color-extract.js b/assets/js/color-extract.js
index 1ed066c6..eb05ab80 100644
--- a/assets/js/color-extract.js
+++ b/assets/js/color-extract.js
@@ -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);
})();
diff --git a/assets/js/core/comment-fixed-input.js b/assets/js/core/comment-fixed-input.js
index 4d0305d4..380cad48 100644
--- a/assets/js/core/comment-fixed-input.js
+++ b/assets/js/core/comment-fixed-input.js
@@ -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;
})();
diff --git a/assets/js/core/misc.js b/assets/js/core/misc.js
index 01dff9df..42c973e2 100644
--- a/assets/js/core/misc.js
+++ b/assets/js/core/misc.js
@@ -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);
+ });
})();
diff --git a/assets/js/credits.js b/assets/js/credits.js
index d084297d..2d28895b 100644
--- a/assets/js/credits.js
+++ b/assets/js/credits.js
@@ -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);
}
})();
diff --git a/assets/js/docs-navigation.js b/assets/js/docs-navigation.js
index 2181fc44..c5e50254 100644
--- a/assets/js/docs-navigation.js
+++ b/assets/js/docs-navigation.js
@@ -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);
+ });
})();
diff --git a/assets/js/download-status.js b/assets/js/download-status.js
index 6041969f..eb807ec3 100644
--- a/assets/js/download-status.js
+++ b/assets/js/download-status.js
@@ -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);
+ });
})();
diff --git a/assets/js/effects.js b/assets/js/effects.js
index 7f0bc497..76101cd8 100644
--- a/assets/js/effects.js
+++ b/assets/js/effects.js
@@ -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 触发
- * 用法:0
- * ============================================================ */
- 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. 倒计时组件
- * 用法:--:--:--
- * ============================================================ */
- 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)
- * 用法:
...
- * ============================================================ */
- 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);
})();
diff --git a/assets/js/enhancements.js b/assets/js/enhancements.js
index 8d3bcb77..617e5389 100644
--- a/assets/js/enhancements.js
+++ b/assets/js/enhancements.js
@@ -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);
});
})();
diff --git a/assets/js/enhancements2.js b/assets/js/enhancements2.js
index 5bad8c27..21b2b662 100644
--- a/assets/js/enhancements2.js
+++ b/assets/js/enhancements2.js
@@ -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 = '
';
-
- 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 += '
' +
- '' + d.getDate() + '' +
- '
';
- }
-
- html += '
';
- 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 = '
';
+ 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 += '
' + d.getDate() + '
';
+ }
+ calendar.innerHTML = html + '
';
+ });
}
- /* ============================================================
- * 初始化入口
- * ============================================================ */
- 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,
};
-
})();
diff --git a/assets/js/follow.js b/assets/js/follow.js
index fd3fd007..199adb1c 100644
--- a/assets/js/follow.js
+++ b/assets/js/follow.js
@@ -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);
})();
diff --git a/assets/js/front-submit.js b/assets/js/front-submit.js
index e1e4c198..6a24c857 100644
--- a/assets/js/front-submit.js
+++ b/assets/js/front-submit.js
@@ -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);
+ });
})();
diff --git a/assets/js/homepage-fixed.js b/assets/js/homepage-fixed.js
index 7ee53c2e..206a7131 100644
--- a/assets/js/homepage-fixed.js
+++ b/assets/js/homepage-fixed.js
@@ -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);
})();
diff --git a/assets/js/input-expand.js b/assets/js/input-expand.js
index 25f57c82..57daf988 100644
--- a/assets/js/input-expand.js
+++ b/assets/js/input-expand.js
@@ -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);
})();
diff --git a/assets/js/loader.js b/assets/js/loader.js
deleted file mode 100644
index ab02a3f8..00000000
--- a/assets/js/loader.js
+++ /dev/null
@@ -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();
- }
-})();
diff --git a/assets/js/main.js b/assets/js/main.js
deleted file mode 100644
index 62545d24..00000000
--- a/assets/js/main.js
+++ /dev/null
@@ -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 () {}
- };
- }
-})();
diff --git a/assets/js/messages.js b/assets/js/messages.js
index cb5d9889..04443acf 100644
--- a/assets/js/messages.js
+++ b/assets/js/messages.js
@@ -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);
})();
diff --git a/assets/js/mini-upload.js b/assets/js/mini-upload.js
index 86906044..6c1b63f1 100644
--- a/assets/js/mini-upload.js
+++ b/assets/js/mini-upload.js
@@ -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;
diff --git a/assets/js/order-center.js b/assets/js/order-center.js
index 9084a5d6..76add5be 100644
--- a/assets/js/order-center.js
+++ b/assets/js/order-center.js
@@ -473,5 +473,4 @@
if (window.AksrtFrontend && typeof window.AksrtFrontend.register === "function") {
window.AksrtFrontend.register("aksrt-order-center", init);
}
- init(document);
}());
diff --git a/assets/js/page-edit.js b/assets/js/page-edit.js
index 6c7d81b5..f1219cf0 100644
--- a/assets/js/page-edit.js
+++ b/assets/js/page-edit.js
@@ -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;
})();
diff --git a/assets/js/page-navs.js b/assets/js/page-navs.js
index 3be89805..93ac4843 100644
--- a/assets/js/page-navs.js
+++ b/assets/js/page-navs.js
@@ -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);
+ });
})();
diff --git a/assets/js/page-template.js b/assets/js/page-template.js
index 08684a39..46b852b3 100644
--- a/assets/js/page-template.js
+++ b/assets/js/page-template.js
@@ -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);
})();
diff --git a/assets/js/pay-vip.js b/assets/js/pay-vip.js
index 5e7fc54a..e097feeb 100644
--- a/assets/js/pay-vip.js
+++ b/assets/js/pay-vip.js
@@ -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);
})();
diff --git a/assets/js/post-share.js b/assets/js/post-share.js
index e6920194..d59a6b6f 100644
--- a/assets/js/post-share.js
+++ b/assets/js/post-share.js
@@ -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();
- }
+ });
})();
diff --git a/assets/js/poster-share.js b/assets/js/poster-share.js
index 15081325..49cc37e3 100644
--- a/assets/js/poster-share.js
+++ b/assets/js/poster-share.js
@@ -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
diff --git a/assets/js/posts-navs-page.js b/assets/js/posts-navs-page.js
index f308ca50..1aa7e7f6 100644
--- a/assets/js/posts-navs-page.js
+++ b/assets/js/posts-navs-page.js
@@ -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);
})();
diff --git a/assets/js/precode.js b/assets/js/precode.js
index 1a611256..1e3b88c3 100644
--- a/assets/js/precode.js
+++ b/assets/js/precode.js
@@ -218,9 +218,7 @@
loadEnlighterJS(initEnlighter);
}
- if (document.readyState === 'loading') {
- document.addEventListener('DOMContentLoaded', init);
- } else {
+ window.AksrtFrontend.register('aksrt-precode', function () {
init();
- }
+ });
})();
diff --git a/assets/js/rehydrate.js b/assets/js/rehydrate.js
index d52f7f37..24640572 100644
--- a/assets/js/rehydrate.js
+++ b/assets/js/rehydrate.js
@@ -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;
}
};
diff --git a/assets/js/report.js b/assets/js/report.js
index 7a721a3d..a851463b 100644
--- a/assets/js/report.js
+++ b/assets/js/report.js
@@ -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);
}
})();
diff --git a/assets/js/reward.js b/assets/js/reward.js
index 2379c8da..279714dd 100644
--- a/assets/js/reward.js
+++ b/assets/js/reward.js
@@ -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();
}
})();
diff --git a/assets/js/routes/user-center.js b/assets/js/routes/user-center.js
index 2ddef274..04e97573 100644
--- a/assets/js/routes/user-center.js
+++ b/assets/js/routes/user-center.js
@@ -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) {
diff --git a/assets/js/runtime/loader.js b/assets/js/runtime/loader.js
index 7bc73922..105ed583 100644
--- a/assets/js/runtime/loader.js
+++ b/assets/js/runtime/loader.js
@@ -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',
diff --git a/assets/js/runtime/main.js b/assets/js/runtime/main.js
index 9070fb86..e638e299 100644
--- a/assets/js/runtime/main.js
+++ b/assets/js/runtime/main.js
@@ -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();
});
diff --git a/assets/js/runtime/main.min.js b/assets/js/runtime/main.min.js
index 4446d1b8..14fc815c 100644
--- a/assets/js/runtime/main.min.js
+++ b/assets/js/runtime/main.min.js
@@ -1 +1 @@
-jQuery.cookie=function(e,a,t){if(a===void 0){var r=null;if(document.cookie&&document.cookie!="")for(var n=document.cookie.split(";"),i=0;i-1||e.indexOf("致命错误")>-1)}function aksrt_sprintf(e){var a=Array.prototype.slice.call(arguments,1),t=aksrt__(e),r=0;return t.replace(/%(\d+\$)?s/g,function(n,i){var s=i?parseInt(i,10)-1:r++;return a[s]!==void 0&&a[s]!==null?a[s]:n})}(function(e,a){var t=a(e,e.document,Date);e.lazySizes=t,typeof module=="object"&&module.exports&&(module.exports=t)})(typeof window<"u"?window:{},function(a,t,r){"use strict";var n,i;if((function(){var w,y={lazyClass:"lazyload",loadedClass:"lazyloaded",loadingClass:"lazyloading",preloadClass:"lazypreload",loadafterClass:"lazyloadafter",errorClass:"lazyerror",autosizesClass:"lazyautosizes",srcAttr:"data-src",srcsetAttr:"data-srcset",sizesAttr:"data-sizes",minSize:40,customMedia:{},init:!0,expFactor:1.5,hFac:.8,loadMode:2,loadHidden:!0,ricTimeout:0,throttleDelay:125};i=a.lazySizesConfig||a.lazysizesConfig||{};for(w in y)w in i||(i[w]=y[w])})(),!t||!t.getElementsByClassName)return{init:function(){},cfg:i,noSupport:!0};var s=t.documentElement,o=a.HTMLPictureElement,d="addEventListener",u="getAttribute",c=a[d].bind(a),l=a.setTimeout,h=a.requestAnimationFrame||l,f=a.requestIdleCallback,p=/^picture$/i,g=["load","error","lazyincluded","_lazyloaded"],v={},b=Array.prototype.forEach,_=function(w,y){return v[y]||(v[y]=new RegExp("(\\s|^)"+y+"(\\s|$)")),v[y].test(w[u]("class")||"")&&v[y]},Q=function(w,y){_(w,y)||w.setAttribute("class",(w[u]("class")||"").trim()+" "+y)},j=function(w,y){var k;(k=_(w,y))&&w.setAttribute("class",(w[u]("class")||"").replace(k," "))},C=function(w,y,k){var L=k?d:"removeEventListener";k&&C(w,y),g.forEach(function(q){w[L](q,y)})},T=function(w,y,k,L,q){var z=t.createEvent("Event");return k||(k={}),k.instance=n,z.initEvent(y,!L,!q),z.detail=k,w.dispatchEvent(z),z},F=function(w,y){var k;!o&&(k=a.picturefill||i.pf)?(y&&y.src&&!w[u]("srcset")&&w.setAttribute("srcset",y.src),k({reevaluate:!0,elements:[w]})):y&&y.src&&(w.src=y.src)},X=function(w,y){return(getComputedStyle(w,null)||{})[y]},Z=function(w,y,k){for(k=k||w.offsetWidth;k49?function(){f(z,{timeout:q}),q!==i.ricTimeout&&(q=i.ricTimeout)}:G(function(){l(z)},!0);return function(E){var A;(E=E===!0)&&(q=33),!y&&(y=!0,A=L-(r.now()-k),A<0&&(A=0),E||A<9?O():l(O,A))}},oe=function(w){var y,k,L=99,q=function(){y=null,w()},z=function(){var O=r.now()-k;O0,H&&X(M,"overflow")!="visible"&&(S=M.getBoundingClientRect(),H=W>S.left&&AS.top-1&&E500&&s.clientWidth>500?500:370:i.expand,n._defEx=U,K=U*i.expFactor,te=i.hFac,J=null,ae2&&L>2&&!t.hidden?(ae=K,ee=0):L>1&&ee>1&&R<6?ae=U:ae=_e),V!==I&&(z=innerWidth+I*te,O=innerHeight+I,B=I*-1,V=I),S=N[x].getBoundingClientRect(),($=S.bottom)>=B&&(E=S.top)<=O&&(W=S.right)>=B*te&&(A=S.left)<=z&&($||W||A||E)&&(i.loadHidden||ue(N[x]))&&(y&&R<3&&!D&&(L<3||ee<4)||we(N[x],I))){if(re(N[x]),H=!0,R>9)break}else!H&&y&&!M&&R<4&&ee<4&&L>2&&(w[0]||i.preloadAfterLoad)&&(w[0]||!D&&($||W||A||E||N[x][u](i.sizesAttr)!="auto"))&&(M=w[0]||N[x])}M&&!H&&re(M)}},P=pe(ce),fe=function(m){var x=m.target;if(x._lazyCache){delete x._lazyCache;return}de(m),Q(x,i.loadedClass),j(x,i.loadingClass),C(x,he),T(x,"lazyloaded"),l(function(){Q(x,i.loadafterClass)},700)},be=G(fe),he=function(m){be({target:m.target})},je=function(m,x){try{m.contentWindow.location.replace(x)}catch{m.src=x}},xe=function(m){var x,S=m[u](i.srcsetAttr);(x=i.customMedia[m[u]("data-media")||m[u]("media")])&&m.setAttribute("media",x),S&&m.setAttribute("srcset",S)},Qe=G(function(m,x,S,M,H){var I,B,D,V,U,K;(U=T(m,"lazybeforeunveil",x)).defaultPrevented||(M&&(S?Q(m,i.autosizesClass):m.setAttribute("sizes",M)),B=m[u](i.srcsetAttr),I=m[u](i.srcAttr),H&&(D=m.parentNode,V=D&&p.test(D.nodeName||"")),K=x.firesLoad||"src"in m&&(B||I||V),U={target:m},Q(m,i.loadingClass),K&&(clearTimeout(k),k=l(de,2500),C(m,he,!0)),V&&b.call(D.getElementsByTagName("source"),xe),B?m.setAttribute("srcset",B):I&&!V&&(ye.test(m.nodeName)?je(m,I):m.src=I),H&&(B||V)&&F(m,{src:I})),m._lazyRace&&delete m._lazyRace,j(m,i.lazyClass),Y(function(){var te=m.complete&&m.naturalWidth>1;(!K||te)&&(te&&Q(m,"ls-is-cached"),fe(U),m._lazyCache=!0,l(function(){"_lazyCache"in m&&delete m._lazyCache},9)),m.loading=="lazy"&&R--},!0)}),re=function(m){if(!m._lazyRace){var x,S=me.test(m.nodeName),M=S&&(m[u](i.sizesAttr)||m[u]("sizes")),H=M=="auto";(H||!y)&&S&&(m[u]("src")||m.srcset)&&!m.complete&&!_(m,i.errorClass)&&_(m,i.lazyClass)||(x=T(m,"lazyunveilread").detail,H&&se.updateElem(m,!0,m.offsetWidth),m._lazyRace=!0,R++,Qe(m,x,H,M,S))}},ke=oe(function(){i.loadMode=3,P()}),ve=function(){i.loadMode==3&&(i.loadMode=2),ke()},ne=function(){if(!y){if(r.now()-q<999){l(ne,999);return}y=!0,i.loadMode=3,P(),c("scroll",ve,!0)}};return{_:function(){q=r.now(),n.elements=t.getElementsByClassName(i.lazyClass),w=t.getElementsByClassName(i.lazyClass+" "+i.preloadClass),c("scroll",P,!0),c("resize",P,!0),c("pageshow",function(m){if(m.persisted){var x=t.querySelectorAll("."+i.loadingClass);x.length&&x.forEach&&h(function(){x.forEach(function(S){S.complete&&re(S)})})}}),a.MutationObserver?new MutationObserver(P).observe(s,{childList:!0,subtree:!0,attributes:!0}):(s[d]("DOMNodeInserted",P,!0),s[d]("DOMAttrModified",P,!0),setInterval(P,999)),c("hashchange",P,!0),["focus","mouseover","click","load","transitionend","animationend"].forEach(function(m){t[d](m,P,!0)}),/d$|^c/.test(t.readyState)?ne():(c("load",ne),t[d]("DOMContentLoaded",P),l(ne,2e4)),n.elements.length?(ce(),Y._lsFlush()):P()},checkElems:P,unveil:re,_aLSL:ve}})(),se=(function(){var w,y=G(function(z,O,E,A){var W,$,J;if(z._lazysizesWidth=A,A+="px",z.setAttribute("sizes",A),p.test(O.nodeName||""))for(W=O.getElementsByTagName("source"),$=0,J=W.length;$-40&&u<40&&c>0?c:0),e.direction=="left"&&(l=0,c=(u>150||u<-150)&&0>c?c:0),e.direction=="top"&&(c=0,l=u>-130&&u<-50&&0>l?l:0),e.direction=="bottom"&&(c=0,l=u>50&&u<130&&l>0?l:0),(c!==0||l!==0)&&(v.preventDefault?v.preventDefault():v.returnValue=!1,f(b,c,l,h,"grab"),jQuery.isFunction(e.onIng)&&e.onIng(t,b,c,l)))}).on("touchend touchcancel pointerup MSPointerUp",g,function(){var v=e.start_selector?e.selector?t.find(e.selector):t.find(e.start_selector):jQuery(this);h&&!r&&(f(v,0,0,"null",""),jQuery.isFunction(e.inEnd)&&e.inEnd(t,v,c,l),(Math.abs(c)>n||Math.abs(l)>n)&&jQuery.isFunction(e.onEnd)&&e.onEnd(t,v,c,l),i=s=o=d=u=c=l=0,h=!1)}).data(a,!0)}},_win.bd=jQuery("body"),_win.window=jQuery(window),_win.is_signin=!!_win.bd.hasClass("logged-in");var _wid=_win.window.width(),_hei=_win.window.height();_win.bd.on("click","[data-close]",function(){var e=jQuery(this).attr("data-close");return jQuery(e).removeClass("show in"),!1}),_win.bd.on("click","[data-toggle-class]",function(){var e=jQuery(this).attr("data-toggle-class")||"show",a=jQuery(this).attr("data-target")||this;return jQuery(a).toggleClass(e).trigger("toggleClass"),!1}),_win.bd.on("click",only_drop),_win.bd.on("toggleClass",".dropup,.dropdown",only_drop);function only_drop(e){var a=jQuery(e.target).closest(".dropup,.dropdown");jQuery(".dropup.open,.dropdown.open").not(a).removeClass("open")}_win.bd.on("click",".alert-dismissible > .close",function(){jQuery(this).parent().slideUp()}),_win.bd.on("click","[data-onclick]",function(){var e=jQuery(this).attr("data-onclick");return jQuery(e).click()}),jQuery.fn.OnlyOn=function(e,a,t,r){var n=/\S+/g,i=!1;e=e.match(n)[0];var s=jQuery._data(this[0],"events");s&&typeof s.type<"u"&&jQuery.each(s[e],function(o,d){if(d.selector==a&&d.data==t)return i=!0,!1}),i?console.log("事件重复绑定{type:"+e+",selector:"+a+",data:"+t+"}"):this.on(e,a,t,r)},jQuery.fn.aksrt_ajax=function(e,a,t,r){return aksrt_ajax(jQuery(this),e,a,t,r)},jQuery.fn.countdown=function(){function e(a,t){var r=new Date,n=r.getTime(),i=new Date(a),s=i.getTime(),o=s-n,d=o/1e3%60;d=d.toFixed(2);var u=~~(o%1e3),c=~~(o/1e3/60%60),l=~~(o/(1e3*60*60)%24),h=~~(o/(1e3*60*60*24));return t==="minute"&&c>0&&(l=0,h=0,c=~~(o/1e3/60)),t==="hour"&&l>0&&(h=0,l=~~(o/(1e3*60*60))),d=d<10?"0"+d:d,c=c<10?"0"+c:c,{total:o,days:h,hours:l,minutes:c,seconds:d,mseconds:u}}jQuery(this).each(function(){var a=jQuery(this),t=a.attr("data-countdown");if(!t)return;var r=a.attr("int-second"),n=a.attr("max-unit");if(a.attr("title",aksrt__("countdown_end_time")+t),r==="auto"){var i=e(t,n);r=i.days>0}function s(){var d=e(t,n);if(r&&(d.seconds=d.seconds.toString().replace(/\.\d+$/,"")),a.find(".day").length&&a.find(".day").html(d.days),a.find(".hour").length&&a.find(".hour").html(d.hours),a.find(".minute").length&&a.find(".minute").html(d.minutes),a.find(".second").length)a.find(".second").html(d.seconds);else{var u="";d.days>0&&(u+=''+d.days+''+aksrt__("countdown_day")+""),(d.hours>0||d.days>0)&&(u+=''+d.hours+''+aksrt__("countdown_hour")+""),(d.minutes>0||d.hours>0||d.days>0)&&(u+=''+d.minutes+''+aksrt__("countdown_minute")+""),u+=''+d.seconds+''+aksrt__("countdown_second")+"",a.html(u)}if(d.total<=0){clearInterval(o);var c=a.attr("data-over-text")||aksrt__("countdown_ended");a.html(c).trigger("countdown-over")}}s();var o=setInterval(s,r?1e3:20);a.removeAttr("data-countdown").addClass("countdown-box")})},_win.dplayer={tbquire:["dplayer"],obj:{}};function new_dplayer(){var e=".new-dplayer:not(.dplayer-initialized),[data-dplayer]:not(.dplayer-initialized)";jQuery(e).length&&jQuery(e).each(function(){var a=jQuery(this);get_new_dplayer(a,function(t){a.addClass("dplayer-initialized").siblings(".dplayer-featured").find(".switch-video").each(function(){var r=jQuery(this),n=r.attr("video-url"),i=r.attr("video-pic");r.data({"video-url":n,"video-pic":i}),r.attr({"dplayer-id":t.container.id}),setTimeout(function(){r.removeAttr("video-url").removeAttr("video-pic")},50)})})})}function get_new_dplayer(e,a){var t={},r=e.attr("video-url")||e.data("video-url"),n=e.attr("data-volume"),i=parseInt((Math.random()+1)*Math.pow(10,4));if(!(e.find(".dplayer-video-wrap").length||!r)){e.attr("id","dplayer-"+i),t.container=document.getElementById("dplayer-"+i),t.theme="#f04494",t.video={url:r,pic:e.attr("video-pic")||"",type:e.attr("video-type")||"auto"},e.attr("data-loop")&&(t.loop=!0),e.attr("data-autoplay")&&(t.autoplay=!0),n&&n<1&&(t.volume=n),n==="none"&&(t.volume=0);var s=e.attr("video-option");if(s){try{s=JSON.parse(s)}catch(d){console.log(d)}jQuery.extend(t,s)}var o=r.toLowerCase();return o.indexOf(".m3u")!=-1&&_win.dplayer.tbquire.push("hls"),o.indexOf(".mpd")!=-1&&_win.dplayer.tbquire.push("dash"),o.indexOf(".flv")!=-1&&_win.dplayer.tbquire.push("flv"),jQuery("link#dplayer").length||jQuery("dplayer").append(''),_win.dplayer.tbquire.push("dplayer"),tbquire(_win.dplayer.tbquire,function(){try{var d=new DPlayer(t);d.on("play",function(){_win.dplayer.play=d}),e.data("dplayer",d),_win.dplayer.obj[i]=d,e.attr({"video-url":"","video-pic":""}),jQuery.isFunction(a)&&a(d)}catch(u){console.error(u)}}),i}}_win.bd.on("click",".swiper-slide.slide-dplayer:not(.slide-dplayer-played) > *",function(){var e=jQuery(this),a=e.find(".new-dplayer").data("dplayer");a&&(a.play(),e.parent().addClass("slide-dplayer-played"))});function thumb_dplayer(e,a){var t=jQuery("body"),r="thumb_dplayer_data",n=t.data(r)||{};if(n[e+a])return;var i="thumb-dplayer-playing",s="dplayer-thumb-hide";function o(h,f,p){f.find(".dplayer-thumb").removeClass(s),_win.dplayer.thumb_play=p,f.find(".progress").show(),h.addClass(i)}function d(h,f,p){p.pause(),f.find(".dplayer-thumb").addClass(s),_win.dplayer.thumb_play=!1,f.find(".progress").hide(),h.removeClass(i)}function u(){if(_win.dplayer.thumb_play){var h=jQuery(_win.dplayer.thumb_play.container).closest(a),f=h.closest(e);d(f,h,_win.dplayer.thumb_play)}}function c(){var h=jQuery(this),f=h.find(a);if(!f.length)return;var p=f.find(".dplayer-thumb").data("dplayer");if(p)return o(h,f,p),p.play();function g(T){T.on("loadeddata",function(){setTimeout(function(){f.find(".progress-bar").css({width:"100%",opacity:"0",transition:"width .2s, opacity .3s .3s"})},100),setTimeout(function(){f.find(".progress").remove()},800)}),setTimeout(function(){o(h,f,T),T.play()},200)}if(!f.find(".dplayer-thumb").length){var v=f.attr("video-url"),b=f.attr("data-volume")||"none",_="",Q=~~f.attr("scale-height"),j='