Worktree/lightbox sitewide #16
@@ -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
|
||||
|
||||
+19
-67
@@ -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') {
|
||||
|
||||
+41
-15
@@ -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('visibilitychange', function () {
|
||||
qrStates.forEach(function (state) {
|
||||
if (document.visibilityState !== 'visible') stopQr(state.root);
|
||||
@@ -692,6 +699,25 @@
|
||||
});
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
|
||||
else init();
|
||||
function initModal() {
|
||||
if (!modal || modal.dataset.aksrtAuthModalInitialized === '1') return;
|
||||
modal.dataset.aksrtAuthModalInitialized = '1';
|
||||
modal.addEventListener('click', function (event) {
|
||||
if (event.target.closest('[data-auth-close]')) closeModal(true);
|
||||
});
|
||||
if (modal.dataset.auto === '1' && Number(window.localStorage.getItem('aksrtAuthAutoUntil') || 0) < Date.now()) {
|
||||
window.setTimeout(function () {
|
||||
var root = modal.querySelector('[data-aksrt-auth]');
|
||||
if (root) openModal(root.dataset.initialTab || 'signin', window.location.href, null);
|
||||
}, Math.max(1, Number(modal.dataset.autoWait) || 5) * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
if (window.AksrtFrontend && typeof window.AksrtFrontend.register === 'function') {
|
||||
window.AksrtFrontend.register('aksrt-auth', function (root) {
|
||||
initGlobal();
|
||||
initRoot(root);
|
||||
initModal();
|
||||
});
|
||||
}
|
||||
}());
|
||||
|
||||
+63
-27
@@ -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);
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -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);
|
||||
})();
|
||||
|
||||
+353
-434
File diff suppressed because one or more lines are too long
@@ -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);
|
||||
})();
|
||||
|
||||
@@ -698,7 +698,7 @@
|
||||
if (preview.balance_enough === false) {
|
||||
if (preview.credits_url) {
|
||||
body += '<a class="but c-red block mt6 aksrt-cashier__recharge" href="' + escapeAttr(preview.credits_url) + '">' +
|
||||
'抱歉!余额不足,请先充值 <i class="ml6 fa fa-angle-right em12" aria-hidden="true"></i></a>';
|
||||
'抱歉!余额不足,请先充值 <i class="ml6 fa fas fa-angle-right em12" aria-hidden="true"></i></a>';
|
||||
} else {
|
||||
body += '<div class="c-red mt6 aksrt-cashier__recharge">抱歉!余额不足,请先充值</div>';
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
})();
|
||||
|
||||
@@ -133,7 +133,7 @@
|
||||
if (!result.success) { notyf((result.data && result.data.message) || result.message || '操作失败', 'danger'); return; }
|
||||
var pinned = !!(result.data && result.data.pinned);
|
||||
btn.setAttribute('data-pinned', pinned ? '1' : '0');
|
||||
btn.innerHTML = '<i class="fa fa-thumbtack mr10 fa-fw" aria-hidden="true"></i>' + (pinned ? '取消置顶' : '设置置顶');
|
||||
btn.innerHTML = '<i class="fa fas fa-thumbtack mr10 fa-fw" aria-hidden="true"></i>' + (pinned ? '取消置顶' : '设置置顶');
|
||||
syncPinnedBadge(commentEl, pinned);
|
||||
notyf(result.message || (pinned ? '评论已置顶。' : '已取消置顶。'), 'success');
|
||||
})
|
||||
@@ -148,7 +148,7 @@
|
||||
badge = document.createElement('badge');
|
||||
badge.className = 'badge-topping jb-blue mr6 flex0';
|
||||
badge.title = '置顶评论';
|
||||
badge.innerHTML = '<i class="fa fa-thumbtack" aria-hidden="true"></i>';
|
||||
badge.innerHTML = '<i class="fa fas fa-thumbtack" aria-hidden="true"></i>';
|
||||
name.insertBefore(badge, name.firstChild);
|
||||
} else if (!pinned && badge) {
|
||||
badge.remove();
|
||||
|
||||
@@ -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.
|
||||
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.querySelector ? root.querySelector('#respond') : document.getElementById('respond');
|
||||
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;
|
||||
})();
|
||||
|
||||
+43
-54
@@ -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);
|
||||
eachMatch(root, ".gradient-bg", renderGradientBackground);
|
||||
}
|
||||
scope.querySelectorAll(".gradient-bg").forEach(renderGradientBackground);
|
||||
}
|
||||
|
||||
document.addEventListener("lazyloaded", function (event) {
|
||||
if (!(event.target instanceof Element) || !event.target.matches(".gradient-bg img")) return;
|
||||
renderGradientBackground(event.target.closest(".gradient-bg"));
|
||||
}, true);
|
||||
|
||||
function initPostThumbMedia(root) {
|
||||
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 () {
|
||||
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")) {
|
||||
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");
|
||||
if (wrapper) {
|
||||
var btn = wrapper.querySelector(".aksrt-hidden-content__submit-btn");
|
||||
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);
|
||||
});
|
||||
})();
|
||||
|
||||
+66
-53
@@ -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() {
|
||||
function bootAssets(root, reason) {
|
||||
if (!balancesRefreshed && reason === 'init') {
|
||||
balancesRefreshed = true;
|
||||
refreshAssetBalances();
|
||||
initSigninGoto();
|
||||
initAffiliateRevenue();
|
||||
initVipShop();
|
||||
initVipPointsExchange();
|
||||
initCardPass();
|
||||
initBalanceCharge();
|
||||
initTransfer();
|
||||
initPointsExchange();
|
||||
initWithdraw();
|
||||
initWithdrawHistory();
|
||||
initAssetTabs();
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', bootAssets);
|
||||
} else {
|
||||
bootAssets();
|
||||
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);
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -18,9 +18,12 @@
|
||||
searchInput: null,
|
||||
items: [],
|
||||
|
||||
init: function () {
|
||||
this.sidebar = document.querySelector('.aksrt-doc-sidebar');
|
||||
if (!this.sidebar) return;
|
||||
init: function (root) {
|
||||
root = root || document;
|
||||
this.sidebar = root.nodeType === 1 && root.matches('.aksrt-doc-sidebar')
|
||||
? root : root.querySelector('.aksrt-doc-sidebar');
|
||||
if (!this.sidebar || this.sidebar.dataset.aksrtDocsNavBound === '1') return;
|
||||
this.sidebar.dataset.aksrtDocsNavBound = '1';
|
||||
|
||||
this.items = Array.from(this.sidebar.querySelectorAll('.aksrt-doc-sidebar__item'));
|
||||
this.searchInput = this.sidebar.querySelector('.aksrt-doc-sidebar__search-input');
|
||||
@@ -129,9 +132,7 @@
|
||||
},
|
||||
};
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', function () { DocsNav.init(); });
|
||||
} else {
|
||||
DocsNav.init();
|
||||
}
|
||||
window.AksrtFrontend.register('aksrt-docs-navigation', function (root) {
|
||||
DocsNav.init(root);
|
||||
});
|
||||
})();
|
||||
|
||||
@@ -13,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);
|
||||
});
|
||||
})();
|
||||
|
||||
Vendored
+58
-81
@@ -10,66 +10,64 @@
|
||||
'use strict';
|
||||
|
||||
var reducedMotion = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||
var countUpObserver = null;
|
||||
var countdownElements = [];
|
||||
var countdownTimer = null;
|
||||
var fpsDetectionStarted = false;
|
||||
|
||||
/* ============================================================
|
||||
* 1. 数字递增 (count-up) — IntersectionObserver 触发
|
||||
* 用法:<span data-aksrt-countup data-target="1234" data-duration="2000">0</span>
|
||||
* ============================================================ */
|
||||
function initCountUp() {
|
||||
if (reducedMotion) return;
|
||||
if (!('IntersectionObserver' in window)) return;
|
||||
function scopeFor(root) {
|
||||
return root && root.querySelectorAll ? root : document;
|
||||
}
|
||||
|
||||
var els = document.querySelectorAll('[data-aksrt-countup]');
|
||||
if (!els.length) return;
|
||||
function eachMatch(root, selector, callback) {
|
||||
var scope = scopeFor(root);
|
||||
if (scope.nodeType === 1 && scope.matches(selector)) callback(scope);
|
||||
scope.querySelectorAll(selector).forEach(callback);
|
||||
}
|
||||
|
||||
var observer = new IntersectionObserver(function (entries) {
|
||||
function animateCountUp(el) {
|
||||
if (el.dataset.aksrtCountupBound === '1') return;
|
||||
el.dataset.aksrtCountupBound = '1';
|
||||
countUpObserver.observe(el);
|
||||
}
|
||||
|
||||
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;
|
||||
observer.unobserve(el);
|
||||
|
||||
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 start = 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;
|
||||
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, ',');
|
||||
}
|
||||
if (progress < 1) requestAnimationFrame(step);
|
||||
else el.textContent = prefix + target.toFixed(dec).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
||||
}
|
||||
|
||||
requestAnimationFrame(step);
|
||||
});
|
||||
}, { threshold: 0.3 });
|
||||
|
||||
els.forEach(function (el) { observer.observe(el); });
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 2. 倒计时组件
|
||||
* 用法:<span data-aksrt-countdown data-end="2026-12-31T23:59:59">--:--:--</span>
|
||||
* ============================================================ */
|
||||
function initCountdown() {
|
||||
var els = document.querySelectorAll('[data-aksrt-countdown]');
|
||||
if (!els.length) return;
|
||||
eachMatch(root, '[data-aksrt-countup]', animateCountUp);
|
||||
}
|
||||
|
||||
function pad(n) { return n < 10 ? '0' + n : '' + n; }
|
||||
|
||||
function update() {
|
||||
function updateCountdowns() {
|
||||
var now = Date.now();
|
||||
els.forEach(function (el) {
|
||||
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) {
|
||||
@@ -81,37 +79,32 @@
|
||||
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) + '秒';
|
||||
}
|
||||
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) + '秒';
|
||||
});
|
||||
}
|
||||
|
||||
update();
|
||||
setInterval(update, 1000);
|
||||
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);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 4. 3D 悬停倾斜 (vanilla tilt)
|
||||
* 用法:<div data-aksrt-tilt data-tilt-max="15">...</div>
|
||||
* ============================================================ */
|
||||
function initTilt() {
|
||||
function initTilt(root) {
|
||||
if (reducedMotion) return;
|
||||
|
||||
document.querySelectorAll('[data-aksrt-tilt]').forEach(function (el) {
|
||||
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');
|
||||
if (Math.round(frames * 1000 / elapsed) < 24 && document.body) document.body.classList.add('fps-accelerat');
|
||||
return;
|
||||
}
|
||||
return; // 只检测一次
|
||||
requestAnimationFrame(countFrames);
|
||||
}
|
||||
requestAnimationFrame(countFrames);
|
||||
}
|
||||
|
||||
requestAnimationFrame(countFrames);
|
||||
function init(root, reason) {
|
||||
initCountUp(root);
|
||||
initCountdown(root);
|
||||
if (typeof initMarquee === 'function') initMarquee(root, reason);
|
||||
initTilt(root);
|
||||
initFpsDetection(root, reason);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 初始化入口
|
||||
* ============================================================ */
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
initCountUp();
|
||||
initCountdown();
|
||||
if (typeof initMarquee === 'function') {
|
||||
initMarquee();
|
||||
}
|
||||
initTilt();
|
||||
initFpsDetection();
|
||||
});
|
||||
|
||||
window.AksrtFrontend.register('aksrt-effects', init);
|
||||
})();
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
})();
|
||||
|
||||
+124
-154
@@ -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) {
|
||||
if (!animateObserver) {
|
||||
animateObserver = 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 () {
|
||||
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);
|
||||
|
||||
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)';
|
||||
}, { threshold: 0.1, rootMargin: '0px 0px -50px 0px' });
|
||||
}
|
||||
|
||||
observer.observe(el);
|
||||
});
|
||||
eachMatch(root, '[data-aksrt-animate]', prepareAnimation);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 5. 粘性元素 (Sticky)
|
||||
* ============================================================ */
|
||||
function initSticky() {
|
||||
document.querySelectorAll('[data-aksrt-sticky]').forEach(function (el) {
|
||||
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 offset = parseInt(el.dataset.aksrtStickyOffset || '0', 10);
|
||||
|
||||
function update() {
|
||||
var rect = el.getBoundingClientRect();
|
||||
var parentRect = el.parentElement.getBoundingClientRect();
|
||||
|
||||
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';
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('scroll', update, { passive: true });
|
||||
});
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 6. 视差滚动
|
||||
* ============================================================ */
|
||||
function initParallax() {
|
||||
var elements = document.querySelectorAll('[data-aksrt-parallax]');
|
||||
if (elements.length === 0) return;
|
||||
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();
|
||||
}
|
||||
|
||||
var ticking = false;
|
||||
|
||||
function update() {
|
||||
var scrollTop = window.pageYOffset;
|
||||
elements.forEach(function (el) {
|
||||
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 windowCenter = window.innerHeight / 2;
|
||||
var offset = (center - windowCenter) * speed;
|
||||
|
||||
var offset = (center - window.innerHeight / 2) * speed;
|
||||
el.style.transform = 'translateY(' + offset + 'px)';
|
||||
});
|
||||
ticking = false;
|
||||
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 (!ticking) {
|
||||
requestAnimationFrame(update);
|
||||
ticking = true;
|
||||
}
|
||||
if (parallaxTicking) return;
|
||||
parallaxTicking = true;
|
||||
requestAnimationFrame(updateParallax);
|
||||
}, { passive: true });
|
||||
}
|
||||
updateParallax();
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 7. 涟漪点击效果
|
||||
* ============================================================ */
|
||||
function initRipple() {
|
||||
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;
|
||||
|
||||
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) {}
|
||||
|
||||
// 生成最近 30 天的格子
|
||||
try { data = JSON.parse(calendar.dataset.aksrtSigninCalendar || '[]'); } catch (e) {}
|
||||
var today = new Date();
|
||||
var html = '<div class="aksrt-signin-calendar__grid">';
|
||||
|
||||
for (var i = 29; i >= 0; i--) {
|
||||
var d = new Date(today);
|
||||
d.setDate(d.getDate() - i);
|
||||
var dateStr = d.toISOString().split('T')[0];
|
||||
var isSigned = data.indexOf(dateStr) !== -1;
|
||||
var isToday = i === 0;
|
||||
|
||||
html += '<div class="aksrt-signin-calendar__day' +
|
||||
(isSigned ? ' is-signed' : '') +
|
||||
(isToday ? ' is-today' : '') +
|
||||
'" title="' + dateStr + (isSigned ? ' ✓' : '') + '">' +
|
||||
'<span>' + d.getDate() + '</span>' +
|
||||
'</div>';
|
||||
html += '<div class="aksrt-signin-calendar__day' + (isSigned ? ' is-signed' : '') + (i === 0 ? ' is-today' : '') +
|
||||
'" title="' + dateStr + (isSigned ? ' ✓' : '') + '"><span>' + d.getDate() + '</span></div>';
|
||||
}
|
||||
calendar.innerHTML = html + '</div>';
|
||||
});
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
calendar.innerHTML = html;
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 初始化入口
|
||||
* ============================================================ */
|
||||
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 init(root, reason) {
|
||||
initTilt(root);
|
||||
initScrollAnimations(root);
|
||||
initRipple(root, reason);
|
||||
initSticky(root);
|
||||
initParallax(root);
|
||||
initFloatLabels(root);
|
||||
initSigninCalendar(root);
|
||||
bindModalLifecycle();
|
||||
}
|
||||
|
||||
window.AksrtFrontend.register('aksrt-enhancements-advanced', init);
|
||||
|
||||
// 暴露到全局供动态内容使用
|
||||
window.AksrtEnhancements = {
|
||||
initTilt: initTilt,
|
||||
initScrollAnimations: initScrollAnimations,
|
||||
initRipple: initRipple,
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
+6
-6
@@ -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);
|
||||
})();
|
||||
|
||||
@@ -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();
|
||||
window.AksrtFrontend.register('aksrt-front-submit', function (root) {
|
||||
App.init(root);
|
||||
});
|
||||
} else {
|
||||
App.init();
|
||||
}
|
||||
})();
|
||||
|
||||
+21
-17
@@ -424,6 +424,7 @@
|
||||
var tablists = (scope || document).querySelectorAll('[data-aksrt-home-tabs]');
|
||||
|
||||
tablists.forEach(function (list, listIndex) {
|
||||
if (list.dataset.aksrtHomeTabsBound === '1') return;
|
||||
var stream = list.closest('.aksrt-homepage__stream');
|
||||
if (!stream) return;
|
||||
|
||||
@@ -431,6 +432,7 @@
|
||||
var panels = Array.from(stream.querySelectorAll('[data-home-tab-panel]'));
|
||||
|
||||
if (buttons.length < 2 || !panels.length) return;
|
||||
list.dataset.aksrtHomeTabsBound = '1';
|
||||
|
||||
function getPanel(button) {
|
||||
var target = button.getAttribute('data-home-tab-target');
|
||||
@@ -539,12 +541,14 @@
|
||||
* Sortbar Dropdown Toggle
|
||||
* ============================================================ */
|
||||
|
||||
function initSortbarDropdown() {
|
||||
document.querySelectorAll('[data-sort-dropdown-trigger]').forEach(function (trigger) {
|
||||
function initSortbarDropdown(scope) {
|
||||
(scope || document).querySelectorAll('[data-sort-dropdown-trigger]').forEach(function (trigger) {
|
||||
if (trigger.dataset.aksrtSortDropdownBound === '1') return;
|
||||
var wrapper = trigger.closest('.aksrt-homepage__sortbar-dropdown');
|
||||
if (!wrapper) return;
|
||||
var menu = wrapper.querySelector('.aksrt-homepage__sortbar-dropdown-menu');
|
||||
if (!menu) return;
|
||||
trigger.dataset.aksrtSortDropdownBound = '1';
|
||||
|
||||
function close() {
|
||||
menu.setAttribute('hidden', '');
|
||||
@@ -599,10 +603,11 @@
|
||||
* Sortbar AJAX
|
||||
* ============================================================ */
|
||||
|
||||
function initSortbar() {
|
||||
document.querySelectorAll('.aksrt-homepage__stream').forEach(function (stream) {
|
||||
function initSortbar(scope) {
|
||||
(scope || document).querySelectorAll('.aksrt-homepage__stream').forEach(function (stream) {
|
||||
var sortbar = stream.querySelector('.aksrt-homepage__sortbar');
|
||||
if (!sortbar || !isSortAjaxEnabled(sortbar)) return;
|
||||
if (!sortbar || !isSortAjaxEnabled(sortbar) || sortbar.dataset.aksrtSortbarBound === '1') return;
|
||||
sortbar.dataset.aksrtSortbarBound = '1';
|
||||
|
||||
sortbar.addEventListener('click', function (event) {
|
||||
var link = event.target.closest('.aksrt-homepage__sortbar-link, .aksrt-homepage__sortbar-dropdown-item');
|
||||
@@ -649,10 +654,11 @@
|
||||
return isNaN(offset) ? 60 : offset;
|
||||
}
|
||||
|
||||
function initStickyTabs() {
|
||||
function initStickyTabs(scope) {
|
||||
if (!isStickyTabsEnabled()) return;
|
||||
|
||||
document.querySelectorAll('.aksrt-homepage__tabs.home-tab-nav-box').forEach(function (tabs) {
|
||||
(scope || document).querySelectorAll('.aksrt-homepage__tabs.home-tab-nav-box').forEach(function (tabs) {
|
||||
if (tabs.dataset.aksrtStickyTabsBound === '1') return;
|
||||
var parent = tabs.parentNode;
|
||||
var sentinel = tabs.previousElementSibling;
|
||||
var canUseSticky = supportsStickyPosition();
|
||||
@@ -660,6 +666,7 @@
|
||||
var observer = null;
|
||||
|
||||
if (!parent || tabs.getAttribute('data-sticky-tabs') === 'false') return;
|
||||
tabs.dataset.aksrtStickyTabsBound = '1';
|
||||
|
||||
if (!sentinel || !sentinel.classList.contains('aksrt-homepage__tabs-sentinel')) {
|
||||
sentinel = document.createElement('div');
|
||||
@@ -718,16 +725,13 @@
|
||||
* Init
|
||||
* ============================================================ */
|
||||
|
||||
function init() {
|
||||
initHomeTabs();
|
||||
initSortbarDropdown();
|
||||
initSortbar();
|
||||
initStickyTabs();
|
||||
function init(root) {
|
||||
var scope = root || document;
|
||||
initHomeTabs(scope);
|
||||
initSortbarDropdown(scope);
|
||||
initSortbar(scope);
|
||||
initStickyTabs(scope);
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', init);
|
||||
} else {
|
||||
init();
|
||||
}
|
||||
window.AksrtFrontend.register('aksrt-homepage', init);
|
||||
})();
|
||||
|
||||
+24
-15
@@ -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);
|
||||
})();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
})();
|
||||
@@ -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 () {}
|
||||
};
|
||||
}
|
||||
})();
|
||||
@@ -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);
|
||||
})();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -473,5 +473,4 @@
|
||||
if (window.AksrtFrontend && typeof window.AksrtFrontend.register === "function") {
|
||||
window.AksrtFrontend.register("aksrt-order-center", init);
|
||||
}
|
||||
init(document);
|
||||
}());
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
*/
|
||||
function PageEdit(options) {
|
||||
this.options = Object.assign({
|
||||
form: null,
|
||||
formSelector: 'form[data-aksrt-edit]',
|
||||
titleSelector: 'input[name="title"], input[name="topic_title"]',
|
||||
contentSelector: 'textarea[name="content"], textarea[name="topic_content"]',
|
||||
@@ -29,7 +30,7 @@
|
||||
draftKey: '',
|
||||
}, options || {});
|
||||
|
||||
this.form = document.querySelector(this.options.formSelector);
|
||||
this.form = this.options.form || document.querySelector(this.options.formSelector);
|
||||
if (!this.form) return;
|
||||
|
||||
this.autoSaveTimer = null;
|
||||
@@ -189,18 +190,15 @@
|
||||
};
|
||||
|
||||
// 自动初始化
|
||||
function autoInit() {
|
||||
var form = document.querySelector('form[data-aksrt-edit]');
|
||||
function autoInit(root) {
|
||||
var form = root && root.nodeType === 1 && root.matches('form[data-aksrt-edit]')
|
||||
? root : (root || document).querySelector('form[data-aksrt-edit]');
|
||||
if (form) {
|
||||
new PageEdit();
|
||||
new PageEdit({ form: form });
|
||||
}
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', autoInit);
|
||||
} else {
|
||||
autoInit();
|
||||
}
|
||||
window.AksrtFrontend.register('aksrt-page-edit', autoInit);
|
||||
|
||||
window.AksrtPageEdit = PageEdit;
|
||||
})();
|
||||
|
||||
+24
-20
@@ -28,7 +28,10 @@
|
||||
searchQuery: '',
|
||||
ajaxInFlight: null,
|
||||
|
||||
init: function () {
|
||||
init: function (root) {
|
||||
this.root = root || document;
|
||||
if (this.root.__aksrtPageNavInitialized) return;
|
||||
this.root.__aksrtPageNavInitialized = true;
|
||||
this.initTocHighlight();
|
||||
this.initSmoothScroll();
|
||||
this.initDocSearch();
|
||||
@@ -40,7 +43,8 @@
|
||||
* TOC 高亮(文档阅读页)
|
||||
* ============================================================ */
|
||||
initTocHighlight: function () {
|
||||
var toc = document.querySelector('.aksrt-doc-toc');
|
||||
var toc = this.root.querySelector('.aksrt-doc-toc');
|
||||
if (this.root.nodeType === 1 && this.root.matches('.aksrt-doc-toc')) toc = this.root;
|
||||
if (!toc) return;
|
||||
|
||||
this.tocItems = Array.from(toc.querySelectorAll('.aksrt-doc-toc__item a'));
|
||||
@@ -92,7 +96,9 @@
|
||||
* 平滑滚动
|
||||
* ============================================================ */
|
||||
initSmoothScroll: function () {
|
||||
document.addEventListener('click', function (e) {
|
||||
if (this.root.__aksrtPageNavSmoothBound) return;
|
||||
this.root.__aksrtPageNavSmoothBound = true;
|
||||
this.root.addEventListener('click', function (e) {
|
||||
var link = e.target.closest('a[href^="#"]');
|
||||
if (!link) return;
|
||||
|
||||
@@ -113,11 +119,11 @@
|
||||
* 文档搜索(AJAX 接管)
|
||||
* ============================================================ */
|
||||
initDocSearch: function () {
|
||||
var searchInput = document.querySelector('.aksrt-doc-search__input');
|
||||
var searchInput = this.root.querySelector('.aksrt-doc-search__input');
|
||||
if (!searchInput) return;
|
||||
|
||||
var resultsContainer = document.querySelector('.aksrt-doc-search__results');
|
||||
var takeover = document.querySelector('.aksrt-doc-takeover');
|
||||
var resultsContainer = this.root.querySelector('.aksrt-doc-search__results');
|
||||
var takeover = this.root.querySelector('.aksrt-doc-takeover');
|
||||
var self = this;
|
||||
|
||||
var debounceTimer = null;
|
||||
@@ -206,7 +212,7 @@
|
||||
resultsContainer.innerHTML = '';
|
||||
}
|
||||
// 显示所有卡片
|
||||
var cards = document.querySelectorAll('.aksrt-doc-index-card');
|
||||
var cards = this.root.querySelectorAll('.aksrt-doc-index-card');
|
||||
cards.forEach(function (card) { card.style.display = ''; });
|
||||
},
|
||||
|
||||
@@ -231,7 +237,7 @@
|
||||
* 分类切换 — AJAX 加载 + 分页
|
||||
* ============================================================ */
|
||||
initCategoryChips: function () {
|
||||
var toolbar = document.querySelector('.aksrt-doc-toolbar');
|
||||
var toolbar = this.root.querySelector('.aksrt-doc-toolbar');
|
||||
if (!toolbar) return;
|
||||
|
||||
var chips = toolbar.querySelectorAll('.aksrt-doc-toolbar__chip[data-cat-id]');
|
||||
@@ -260,7 +266,7 @@
|
||||
}
|
||||
|
||||
var self = this;
|
||||
var grid = document.querySelector('.aksrt-doc-grid');
|
||||
var grid = this.root.querySelector('.aksrt-doc-grid');
|
||||
if (!grid) return;
|
||||
|
||||
// 显示加载状态
|
||||
@@ -305,7 +311,7 @@
|
||||
},
|
||||
|
||||
updateMetaCount: function (total) {
|
||||
var meta = document.querySelector('.aksrt-doc-toolbar__meta');
|
||||
var meta = this.root.querySelector('.aksrt-doc-toolbar__meta');
|
||||
if (meta) {
|
||||
meta.textContent = total + ' 篇文档';
|
||||
}
|
||||
@@ -316,7 +322,7 @@
|
||||
* ============================================================ */
|
||||
initPagination: function () {
|
||||
var self = this;
|
||||
var paginationContainer = document.querySelector('.aksrt-doc-pagination');
|
||||
var paginationContainer = this.root.querySelector('.aksrt-doc-pagination');
|
||||
if (!paginationContainer) return;
|
||||
|
||||
paginationContainer.addEventListener('click', function (e) {
|
||||
@@ -331,7 +337,7 @@
|
||||
self.loadCategoryDocs(self.activeCategory, page);
|
||||
|
||||
// 滚动到顶部
|
||||
var grid = document.querySelector('.aksrt-doc-grid');
|
||||
var grid = self.root.querySelector('.aksrt-doc-grid');
|
||||
if (grid) {
|
||||
grid.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
}
|
||||
@@ -342,7 +348,7 @@
|
||||
this.totalPages = totalPages;
|
||||
this.currentPage = currentPage;
|
||||
|
||||
var container = document.querySelector('.aksrt-doc-pagination');
|
||||
var container = this.root.querySelector('.aksrt-doc-pagination');
|
||||
if (!container) return;
|
||||
|
||||
if (totalPages <= 1) {
|
||||
@@ -394,7 +400,7 @@
|
||||
},
|
||||
|
||||
filterDocItems: function (query) {
|
||||
var cards = document.querySelectorAll('.aksrt-doc-index-card');
|
||||
var cards = this.root.querySelectorAll('.aksrt-doc-index-card');
|
||||
if (cards.length > 0) {
|
||||
cards.forEach(function (card) {
|
||||
var title = card.querySelector('.aksrt-doc-index-card__title');
|
||||
@@ -408,7 +414,7 @@
|
||||
});
|
||||
}
|
||||
|
||||
var sidebarItems = document.querySelectorAll('.aksrt-doc-sidebar__item');
|
||||
var sidebarItems = this.root.querySelectorAll('.aksrt-doc-sidebar__item');
|
||||
if (sidebarItems.length > 0) {
|
||||
sidebarItems.forEach(function (item) {
|
||||
var link = item.querySelector('.aksrt-doc-sidebar__link');
|
||||
@@ -446,9 +452,7 @@
|
||||
}
|
||||
};
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', function () { PAGE_NAVS.init(); });
|
||||
} else {
|
||||
PAGE_NAVS.init();
|
||||
}
|
||||
window.AksrtFrontend.register('aksrt-page-navs', function (root) {
|
||||
PAGE_NAVS.init(root);
|
||||
});
|
||||
})();
|
||||
|
||||
+22
-13
@@ -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);
|
||||
})();
|
||||
|
||||
@@ -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);
|
||||
})();
|
||||
|
||||
@@ -271,7 +271,11 @@
|
||||
return Promise.resolve({ mode: 'window' });
|
||||
}
|
||||
|
||||
var genericShareBound = false;
|
||||
|
||||
function bindGenericShareButtons() {
|
||||
if (genericShareBound) return;
|
||||
genericShareBound = true;
|
||||
document.addEventListener('click', function (event) {
|
||||
var node = event.target.closest('[data-share-platform]');
|
||||
if (!node || node.closest('#share-dropdown')) return;
|
||||
@@ -299,9 +303,7 @@
|
||||
bindGenericShareButtons();
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', init);
|
||||
} else {
|
||||
window.AksrtFrontend.register('aksrt-post-share', function () {
|
||||
init();
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
+16
-16
@@ -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
|
||||
|
||||
@@ -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);
|
||||
})();
|
||||
|
||||
@@ -218,9 +218,7 @@
|
||||
loadEnlighterJS(initEnlighter);
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', init);
|
||||
} else {
|
||||
window.AksrtFrontend.register('aksrt-precode', function () {
|
||||
init();
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
+44
-16
@@ -7,7 +7,8 @@
|
||||
*
|
||||
* Usage:
|
||||
* AksrtFrontend.register('name', initFn); // Register a component
|
||||
* AksrtFrontend.rehydrate(root, 'init'); // Initialize all components
|
||||
* AksrtFrontend.boot(document); // One-time initial page load
|
||||
* AksrtFrontend.rehydrate(root, 'ajax'); // Initialize dynamic content
|
||||
*
|
||||
* @package AKSRT
|
||||
* @since 5.0.0
|
||||
@@ -16,7 +17,25 @@
|
||||
'use strict';
|
||||
|
||||
var _registry = [];
|
||||
var _initialized = [];
|
||||
var _booted = false;
|
||||
var _bootRoot = null;
|
||||
|
||||
function invoke(entry, root, reason) {
|
||||
try {
|
||||
entry.initFn(root, reason);
|
||||
} catch (err) {
|
||||
console.error('[AKSRT Rehydrate] Error initializing "' + entry.name + '":', err);
|
||||
}
|
||||
}
|
||||
|
||||
function dispatch(root, reason, eventName) {
|
||||
try {
|
||||
root.dispatchEvent(new CustomEvent(eventName, {
|
||||
bubbles: true,
|
||||
detail: { reason: reason }
|
||||
}));
|
||||
} catch (e) { /* IE fallback */ }
|
||||
}
|
||||
|
||||
window.AksrtFrontend = {
|
||||
|
||||
@@ -32,10 +51,26 @@
|
||||
for (var i = 0; i < _registry.length; i++) {
|
||||
if (_registry[i].name === name) {
|
||||
_registry[i].initFn = initFn;
|
||||
if (_booted) invoke(_registry[i], _bootRoot || document, 'init');
|
||||
return;
|
||||
}
|
||||
}
|
||||
_registry.push({ name: name, initFn: initFn });
|
||||
var entry = { name: name, initFn: initFn };
|
||||
_registry.push(entry);
|
||||
if (_booted) invoke(entry, _bootRoot || document, 'init');
|
||||
},
|
||||
|
||||
/**
|
||||
* Run the one-time initial page boot.
|
||||
*
|
||||
* @param {Element|Document} root The document root to initialize
|
||||
*/
|
||||
boot: function (root) {
|
||||
if (_booted) return;
|
||||
_booted = true;
|
||||
_bootRoot = root || document;
|
||||
this.rehydrate(_bootRoot, 'init');
|
||||
dispatch(_bootRoot, 'init', 'aksrt:ready');
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -53,21 +88,10 @@
|
||||
reason = reason || 'init';
|
||||
|
||||
for (var i = 0; i < _registry.length; i++) {
|
||||
var entry = _registry[i];
|
||||
try {
|
||||
entry.initFn(root, reason);
|
||||
} catch (err) {
|
||||
console.error('[AKSRT Rehydrate] Error initializing "' + entry.name + '":', err);
|
||||
}
|
||||
invoke(_registry[i], root, reason);
|
||||
}
|
||||
|
||||
// Dispatch event so external scripts can hook in
|
||||
try {
|
||||
root.dispatchEvent(new CustomEvent('aksrt:rehydrated', {
|
||||
bubbles: true,
|
||||
detail: { reason: reason }
|
||||
}));
|
||||
} catch (e) { /* IE fallback */ }
|
||||
dispatch(root, reason, 'aksrt:rehydrated');
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -75,6 +99,10 @@
|
||||
*/
|
||||
getRegistered: function () {
|
||||
return _registry.map(function (r) { return r.name; });
|
||||
},
|
||||
|
||||
isBooted: function () {
|
||||
return _booted;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+4
-5
@@ -141,6 +141,8 @@
|
||||
}
|
||||
|
||||
function initReportButtons() {
|
||||
if (document.documentElement.dataset.aksrtReportInitialized === '1') return;
|
||||
document.documentElement.dataset.aksrtReportInitialized = '1';
|
||||
document.addEventListener('click', function (e) {
|
||||
var btn = e.target.closest('[data-aksrt-report]');
|
||||
if (!btn) return;
|
||||
@@ -157,10 +159,7 @@
|
||||
});
|
||||
}
|
||||
|
||||
// Auto-init on DOMContentLoaded
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initReportButtons);
|
||||
} else {
|
||||
initReportButtons();
|
||||
if (window.AksrtFrontend && typeof window.AksrtFrontend.register === 'function') {
|
||||
window.AksrtFrontend.register('aksrt-report', initReportButtons);
|
||||
}
|
||||
})();
|
||||
|
||||
+4
-5
@@ -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();
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -42,8 +42,10 @@
|
||||
|
||||
/* ==================== Dashboard 导航 ==================== */
|
||||
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,7 +393,7 @@
|
||||
});
|
||||
}
|
||||
|
||||
function initPostDeletion() {
|
||||
function initPostDeletion(root) {
|
||||
if (document.documentElement.dataset.aksrtPostDeletionBound === 'true') return;
|
||||
document.documentElement.dataset.aksrtPostDeletionBound = 'true';
|
||||
document.addEventListener('click', function(e) {
|
||||
@@ -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,41 +1033,24 @@
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
function initNavigationOnce() {
|
||||
initDashboardNavigation();
|
||||
initPostDeletion();
|
||||
}
|
||||
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
initDashboardNavigation();
|
||||
initProfileForm();
|
||||
initAuthForm();
|
||||
initUnfavorite();
|
||||
initPostDeletion();
|
||||
initNotifications();
|
||||
initNotificationPreferences();
|
||||
initSettings();
|
||||
initBindPhone();
|
||||
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();
|
||||
});
|
||||
} else {
|
||||
initDashboardNavigation();
|
||||
initProfileForm();
|
||||
initAuthForm();
|
||||
initUnfavorite();
|
||||
initPostDeletion();
|
||||
initNotifications();
|
||||
initNotificationPreferences();
|
||||
initSettings();
|
||||
initBindPhone();
|
||||
initSettingsCallbackToast();
|
||||
}
|
||||
|
||||
// 绑定手机
|
||||
|
||||
@@ -59,17 +59,8 @@ tbquire.config({
|
||||
'translate' : 'libs/translate.min',
|
||||
'waterfall' : 'waterfall.min',
|
||||
'enlighterjs' : 'enlighter/enlighterjs.min',
|
||||
'section-navs' : 'section-navs.min',
|
||||
|
||||
'poster-share' : 'poster-share.min',
|
||||
'comment' : 'comment.min',
|
||||
'page-template' : 'page-template.min',
|
||||
'page-edit' : 'page-edit.min',
|
||||
'author' : 'author.min',
|
||||
'page-navs' : 'page-navs.min',
|
||||
'input-expand' : 'input-expand.min',
|
||||
'mini-touch' : 'mini-touch.min',
|
||||
'mini-upload' : 'mini-upload.min',
|
||||
'editextend' : 'editextend.min',
|
||||
'petite-vue' : 'libs/petite-vue.iife',
|
||||
'svg-icon' : 'svg-icon',
|
||||
|
||||
+16
-39
@@ -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();
|
||||
});
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -1,46 +0,0 @@
|
||||
//文章导航
|
||||
jQuery("button[evt='action']").on("click", function (t) {
|
||||
t = t || window.event;
|
||||
var a = t.target || t.srcElement,
|
||||
e = jQuery(a),
|
||||
n = e.parents("form"),
|
||||
r = n.serializeObject(),
|
||||
c = [];
|
||||
return jQuery("#cat-sortable-ok .sortable-cat-item").each(function () {
|
||||
c.push(jQuery(this).attr("data-id"));
|
||||
}), r.navs_show_cat_id = c, save_userdata(r, aksrt__("save_success"), "reload"), !1;
|
||||
});
|
||||
|
||||
function save_userdata(b, c, d) {
|
||||
notyf(aksrt__("processing_wait"), "load", "", "user_ajax"),
|
||||
c = c || aksrt__("done");
|
||||
jQuery.ajax({
|
||||
type: "POST",
|
||||
url: _win.uri + '/action/post_navs.php',
|
||||
data: b,
|
||||
dataType: "json",
|
||||
success: function (n) {
|
||||
if (n.error) {
|
||||
n.msg && notyf(n.msg, (n.error ? 'danger' : ""), "", "user_ajax");
|
||||
} else {
|
||||
notyf(n.msg || c, "", "", "user_ajax");
|
||||
"reload" == d && location.reload();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
jQuery(document).ready(function () {
|
||||
jQuery("#cat-sortable").length && tbquire(["sortablejs"], function () {
|
||||
var e = document.getElementById("cat-sortable"),
|
||||
t = document.getElementById("cat-sortable-ok"),
|
||||
a = {
|
||||
group: "cat_shared",
|
||||
multiDrag: !0,
|
||||
chosenClass: "chosen",
|
||||
fallbackClass: !0,
|
||||
animation: 400
|
||||
};
|
||||
Sortable.create(e, a), Sortable.create(t, a);
|
||||
});
|
||||
});
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
function save_userdata(a,t,e){notyf(aksrt__("processing_wait"),"load","","user_ajax"),t=t||aksrt__("done"),jQuery.ajax({type:"POST",url:_win.uri+"/action/post_navs.php",data:a,dataType:"json",success:function(a){a.error?a.msg&¬yf(a.msg,a.error?"danger":"","","user_ajax"):(notyf(a.msg||t,"","","user_ajax"),"reload"==e&&location.reload())}})}jQuery("button[evt='action']").on("click",function(a){a=a||window.event;var t=a.target||a.srcElement,e=jQuery(t),o=e.parents("form"),r=o.serializeObject(),s=[];return jQuery("#cat-sortable-ok .sortable-cat-item").each(function(){s.push(jQuery(this).attr("data-id"))}),r.navs_show_cat_id=s,save_userdata(r,aksrt__("save_success"),"reload"),!1}),jQuery(document).ready(function(){jQuery("#cat-sortable").length&&tbquire(["sortablejs"],function(){var a=document.getElementById("cat-sortable"),t=document.getElementById("cat-sortable-ok"),e={group:"cat_shared",multiDrag:!0,chosenClass:"chosen",fallbackClass:!0,animation:400};Sortable.create(a,e),Sortable.create(t,e)})});
|
||||
+24
-19
@@ -40,8 +40,10 @@
|
||||
return count >= MIN_HEADINGS ? html : '';
|
||||
}
|
||||
|
||||
function fillBoxes(listsHtml) {
|
||||
document.querySelectorAll(NAVBOX).forEach(function (box) {
|
||||
function fillBoxes(listsHtml, scope) {
|
||||
var boxes = Array.prototype.slice.call(scope.querySelectorAll(NAVBOX));
|
||||
if (scope.nodeType === 1 && scope.matches(NAVBOX)) boxes.unshift(scope);
|
||||
boxes.forEach(function (box) {
|
||||
var existing = box.querySelector('.' + NAV_CLASS);
|
||||
if (existing) {
|
||||
existing.innerHTML = listsHtml;
|
||||
@@ -75,7 +77,13 @@
|
||||
window.scrollTo({ top: top, behavior: 'smooth' });
|
||||
}
|
||||
|
||||
var clicksBound = false;
|
||||
var scrollspyBound = false;
|
||||
var autoHashHandled = false;
|
||||
|
||||
function bindClicks() {
|
||||
if (clicksBound) return;
|
||||
clicksBound = true;
|
||||
document.addEventListener('click', function (e) {
|
||||
var a = e.target && e.target.closest ? e.target.closest('.' + NAV_CLASS + ' a[href^="#"]') : null;
|
||||
if (!a) return;
|
||||
@@ -87,9 +95,11 @@
|
||||
});
|
||||
}
|
||||
|
||||
function scrollspy() {
|
||||
var links = document.querySelectorAll('.' + NAV_CLASS + ' a[href^="#"]');
|
||||
function scrollspy(scope) {
|
||||
if (scrollspyBound) return;
|
||||
var links = scope.querySelectorAll('.' + NAV_CLASS + ' a[href^="#"]');
|
||||
if (!links.length) return;
|
||||
scrollspyBound = true;
|
||||
var map = [];
|
||||
links.forEach(function (a) {
|
||||
var id = a.getAttribute('href').slice(1);
|
||||
@@ -111,37 +121,32 @@
|
||||
}
|
||||
|
||||
function autoHash() {
|
||||
if (window.location.hash) {
|
||||
if (autoHashHandled || !window.location.hash) return;
|
||||
autoHashHandled = true;
|
||||
setTimeout(function () {
|
||||
smoothTo(window.location.hash);
|
||||
}, 40);
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
function init(scope) {
|
||||
scope = scope || document;
|
||||
if (document.querySelector('.posts-nav-box .toc-list, .posts-nav-box.toc-widget .toc-list')) {
|
||||
return;
|
||||
}
|
||||
var root = document.querySelector('[data-nav], .article-content, .entry-content, main.article');
|
||||
var root = scope.nodeType === 1 && scope.matches('[data-nav], .article-content, .entry-content, main.article')
|
||||
? scope
|
||||
: scope.querySelector('[data-nav], .article-content, .entry-content, main.article');
|
||||
if (!root) return;
|
||||
var listsHtml = buildLists(root);
|
||||
if (!listsHtml) return;
|
||||
if (!document.querySelector(NAVBOX) && !document.querySelector('.' + NAV_CLASS)) {
|
||||
return;
|
||||
}
|
||||
fillBoxes(listsHtml);
|
||||
fillBoxes(listsHtml, document);
|
||||
bindClicks();
|
||||
scrollspy();
|
||||
scrollspy(document);
|
||||
autoHash();
|
||||
}
|
||||
|
||||
if (window.AksrtFrontend && typeof window.AksrtFrontend.register === 'function') {
|
||||
window.AksrtFrontend.register('aksrt-section-navs', function () {
|
||||
init();
|
||||
});
|
||||
} else if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', init);
|
||||
} else {
|
||||
init();
|
||||
}
|
||||
window.AksrtFrontend.register('aksrt-section-navs', init);
|
||||
})();
|
||||
|
||||
+17
-12
@@ -29,8 +29,11 @@
|
||||
});
|
||||
}
|
||||
|
||||
function initSignin() {
|
||||
var buttons = Array.prototype.slice.call(document.querySelectorAll('[data-signin-btn]'));
|
||||
function initSignin(scope) {
|
||||
scope = scope || document;
|
||||
var buttons = [];
|
||||
if (scope.nodeType === 1 && scope.matches('[data-signin-btn]')) buttons.push(scope);
|
||||
if (scope.querySelectorAll) scope.querySelectorAll('[data-signin-btn]').forEach(function (button) { buttons.push(button); });
|
||||
var freshButtons = buttons.filter(function (button) {
|
||||
return button.dataset.aksrtSigninInitialized !== '1';
|
||||
});
|
||||
@@ -40,12 +43,19 @@
|
||||
button.dataset.aksrtSigninInitialized = '1';
|
||||
});
|
||||
|
||||
function elements(selector) {
|
||||
var items = [];
|
||||
if (scope.nodeType === 1 && scope.matches(selector)) items.push(scope);
|
||||
if (scope.querySelectorAll) scope.querySelectorAll(selector).forEach(function (item) { items.push(item); });
|
||||
return items;
|
||||
}
|
||||
|
||||
function statuses() {
|
||||
return document.querySelectorAll('[data-signin-status]');
|
||||
return elements('[data-signin-status]');
|
||||
}
|
||||
|
||||
function currentButtons() {
|
||||
return document.querySelectorAll('[data-signin-btn]');
|
||||
return elements('[data-signin-btn]');
|
||||
}
|
||||
|
||||
function setStatus(text) {
|
||||
@@ -98,7 +108,8 @@
|
||||
}
|
||||
|
||||
function captchaMount() {
|
||||
return document.querySelector('[data-signin-captcha]');
|
||||
if (scope.nodeType === 1 && scope.matches('[data-signin-captcha]')) return scope;
|
||||
return scope.querySelector ? scope.querySelector('[data-signin-captcha]') : null;
|
||||
}
|
||||
|
||||
function doSignin(captchaPayload) {
|
||||
@@ -115,7 +126,7 @@
|
||||
}
|
||||
|
||||
notyf(result.json.message || '签到成功', 'success', 5, 'aksrt-balance-signin-toast');
|
||||
document.querySelectorAll('[data-credits-value]').forEach(function (element) {
|
||||
elements('[data-credits-value]').forEach(function (element) {
|
||||
element.textContent = Number(result.json.balance || 0).toLocaleString();
|
||||
});
|
||||
setButtonState('done');
|
||||
@@ -149,12 +160,6 @@
|
||||
refresh();
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initSignin);
|
||||
} else {
|
||||
initSignin();
|
||||
}
|
||||
|
||||
if (window.AksrtFrontend && typeof window.AksrtFrontend.register === 'function') {
|
||||
window.AksrtFrontend.register('signin', initSignin);
|
||||
}
|
||||
|
||||
@@ -10,8 +10,11 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var el = document.getElementById('aksrt-site-notice');
|
||||
if (!el) return;
|
||||
window.AksrtFrontend.register('aksrt-site-notice', function (root) {
|
||||
root = root || document;
|
||||
var el = root.nodeType === 1 && root.matches('#aksrt-site-notice') ? root : root.querySelector('#aksrt-site-notice');
|
||||
if (!el || el.dataset.aksrtNoticeBound === '1') return;
|
||||
el.dataset.aksrtNoticeBound = '1';
|
||||
|
||||
// 弹窗周期(小时),0=永不过期
|
||||
var expiresHours = parseInt(el.dataset.expires || '24', 10) || 0;
|
||||
@@ -88,4 +91,5 @@
|
||||
// Delay slightly so it doesn't flash on fast navigations
|
||||
setTimeout(show, 500);
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
if (typeof window.notyf === 'function') window.notyf(message, type);
|
||||
}
|
||||
|
||||
function bindOnce() {
|
||||
if (document.__aksrtUserBadgeActionsBound) return;
|
||||
document.__aksrtUserBadgeActionsBound = true;
|
||||
document.addEventListener('click', function (event) {
|
||||
var button = event.target.closest('[data-aksrt-badge-action]');
|
||||
if (!button || button.classList.contains('is-loading')) return;
|
||||
@@ -57,4 +60,7 @@
|
||||
notice(error.message || '网络错误', 'danger');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
window.AksrtFrontend.register('aksrt-user-badge-actions', bindOnce);
|
||||
})(window, document);
|
||||
|
||||
@@ -219,6 +219,9 @@
|
||||
};
|
||||
|
||||
// ── 剧集切换按钮事件委托 ──
|
||||
function bindEpisodeSwitch() {
|
||||
if (document.__aksrtVideoEpisodeBound) return;
|
||||
document.__aksrtVideoEpisodeBound = true;
|
||||
document.addEventListener('click', function (e) {
|
||||
var switchBtn = e.target.closest('.switch-video, .switch-iframe');
|
||||
if (!switchBtn) return;
|
||||
@@ -257,23 +260,23 @@
|
||||
switchBtn.classList.add('is-active');
|
||||
switchBtn.classList.add('active');
|
||||
});
|
||||
}
|
||||
|
||||
// ── Public API ──
|
||||
|
||||
window.AksrtVideoPlayer = AksrtVideoPlayer;
|
||||
|
||||
// ── Auto-init ──
|
||||
|
||||
function init() {
|
||||
function init(root) {
|
||||
root = root || document;
|
||||
injectStyle();
|
||||
document.querySelectorAll('[data-aksrt-video]').forEach(function (el) {
|
||||
bindEpisodeSwitch();
|
||||
var elements = [];
|
||||
if (root && root.nodeType === 1 && root.matches('[data-aksrt-video]')) elements.push(root);
|
||||
Array.prototype.push.apply(elements, root.querySelectorAll('[data-aksrt-video]'));
|
||||
elements.forEach(function (el) {
|
||||
new AksrtVideoPlayer(el);
|
||||
});
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', init);
|
||||
} else {
|
||||
init();
|
||||
}
|
||||
window.AksrtFrontend.register('aksrt-video-player', init);
|
||||
})();
|
||||
|
||||
+16
-8
@@ -154,24 +154,32 @@
|
||||
});
|
||||
}
|
||||
|
||||
function autoInit() {
|
||||
document.querySelectorAll('[data-aksrt-waterfall]').forEach(function (el) {
|
||||
function autoInit(root) {
|
||||
var elements = [];
|
||||
if (root && root.nodeType === 1 && root.matches('[data-aksrt-waterfall]')) elements.push(root);
|
||||
Array.prototype.push.apply(elements, (root || document).querySelectorAll('[data-aksrt-waterfall]'));
|
||||
elements.forEach(function (el) {
|
||||
if (el._aksrtWaterfall) return;
|
||||
var cols = parseInt(el.dataset.aksrtWaterfallColumns) || 0;
|
||||
var gap = parseInt(el.dataset.aksrtWaterfallGap) || 16;
|
||||
waterfallInstances.push(new Waterfall(el, { columns: cols, gap: gap }));
|
||||
el._aksrtWaterfall = new Waterfall(el, { columns: cols, gap: gap });
|
||||
waterfallInstances.push(el._aksrtWaterfall);
|
||||
});
|
||||
}
|
||||
|
||||
function bindGlobalEvents() {
|
||||
if (document.__aksrtWaterfallEventsBound) return;
|
||||
document.__aksrtWaterfallEventsBound = true;
|
||||
document.addEventListener('post_ajax.ed', relayoutAll);
|
||||
document.addEventListener('aksrt:posts:rendered', relayoutAll);
|
||||
document.addEventListener('lazyloaded', relayoutAll, true);
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', autoInit);
|
||||
} else {
|
||||
autoInit();
|
||||
}
|
||||
|
||||
window.AksrtFrontend.register('aksrt-waterfall', function (root) {
|
||||
bindGlobalEvents();
|
||||
autoInit(root);
|
||||
});
|
||||
|
||||
// Export to global
|
||||
window.AksrtWaterfall = Waterfall;
|
||||
window.AksrtInfiniteScroll = InfiniteScroll;
|
||||
|
||||
+5
-2
@@ -249,7 +249,10 @@
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
document.querySelectorAll('[data-aksrt-yiyan]').forEach(initYiyan);
|
||||
window.AksrtFrontend.register('aksrt-yiyan', function (root) {
|
||||
var elements = [];
|
||||
if (root && root.nodeType === 1 && root.matches('[data-aksrt-yiyan]')) elements.push(root);
|
||||
Array.prototype.push.apply(elements, (root || document).querySelectorAll('[data-aksrt-yiyan]'));
|
||||
elements.forEach(initYiyan);
|
||||
});
|
||||
})();
|
||||
|
||||
+21
-21
@@ -166,7 +166,7 @@
|
||||
}
|
||||
if (data.paginate_html) container.insertAdjacentHTML('beforeend', data.paginate_html);
|
||||
container.dataset.page = String(data.page || page);
|
||||
scan(container);
|
||||
window.AksrtFrontend.rehydrate(container, 'ajax');
|
||||
})
|
||||
.catch(function () { container.innerHTML = errorMarkup(); })
|
||||
.finally(function () {
|
||||
@@ -262,28 +262,28 @@
|
||||
requestAnimationFrame(frame);
|
||||
}
|
||||
|
||||
function elementsIn(root, selector) {
|
||||
var scope = root || document;
|
||||
var elements = [];
|
||||
if (scope.matches && scope.matches(selector)) elements.push(scope);
|
||||
if (scope.querySelectorAll) {
|
||||
scope.querySelectorAll(selector).forEach(function (element) { elements.push(element); });
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
|
||||
function scan(root) {
|
||||
var scope = root || document;
|
||||
scope.querySelectorAll('.aksrt-widget-video[data-video-url]').forEach(initVideo);
|
||||
scope.querySelectorAll('.aksrt-widget-toc').forEach(initToc);
|
||||
scope.querySelectorAll('.aksrt-widget-quote').forEach(initQuote);
|
||||
scope.querySelectorAll('[data-widget-items]').forEach(initItems);
|
||||
scope.querySelectorAll('.aksrt-widget-tabs, .widget-tab-post').forEach(initTabs);
|
||||
scope.querySelectorAll('.aksrt-faq').forEach(initFaq);
|
||||
scope.querySelectorAll('.aksrt-feature-intro').forEach(initFeatures);
|
||||
scope.querySelectorAll('[data-count-up]').forEach(initCount);
|
||||
if (typeof window.VanillaTilt !== 'undefined') scope.querySelectorAll('[data-aksrt-tilt]').forEach(function (el) { if (once(el, 'Tilt')) window.VanillaTilt.init(el); });
|
||||
elementsIn(scope, '.aksrt-widget-video[data-video-url]').forEach(initVideo);
|
||||
elementsIn(scope, '.aksrt-widget-toc').forEach(initToc);
|
||||
elementsIn(scope, '.aksrt-widget-quote').forEach(initQuote);
|
||||
elementsIn(scope, '[data-widget-items]').forEach(initItems);
|
||||
elementsIn(scope, '.aksrt-widget-tabs, .widget-tab-post').forEach(initTabs);
|
||||
elementsIn(scope, '.aksrt-faq').forEach(initFaq);
|
||||
elementsIn(scope, '.aksrt-feature-intro').forEach(initFeatures);
|
||||
elementsIn(scope, '[data-count-up]').forEach(initCount);
|
||||
if (typeof window.VanillaTilt !== 'undefined') elementsIn(scope, '[data-aksrt-tilt]').forEach(function (el) { if (once(el, 'Tilt')) window.VanillaTilt.init(el); });
|
||||
}
|
||||
|
||||
function ready() {
|
||||
scan(document);
|
||||
if ('MutationObserver' in window) {
|
||||
new MutationObserver(function (mutations) {
|
||||
mutations.forEach(function (mutation) { mutation.addedNodes.forEach(function (node) { if (node.nodeType === 1) scan(node); }); });
|
||||
}).observe(document.body, { childList: true, subtree: true });
|
||||
}
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', ready);
|
||||
else ready();
|
||||
window.AksrtFrontend.register('aksrt-widgets', scan);
|
||||
})();
|
||||
|
||||
@@ -403,7 +403,7 @@ if (!function_exists('aksrt_comments_render_signarea')) :
|
||||
<div class="comment-signarea text-center box-body radius8">
|
||||
<h3 class="text-muted em12 theme-box muted-3-color"><?php esc_html_e('请登录后发表评论', 'aksrt'); ?></h3>
|
||||
<p>
|
||||
<a href="javascript:;" data-login-url="<?php echo esc_url($login_url); ?>" class="signin-loader but c-blue padding-lg"><i class="fa fa-fw fa-sign-in mr10" aria-hidden="true"></i><?php esc_html_e('登录', 'aksrt'); ?></a>
|
||||
<a href="javascript:;" data-login-url="<?php echo esc_url($login_url); ?>" class="signin-loader but c-blue padding-lg"><i class="fa fas fa-fw fa-sign-in-alt mr10" aria-hidden="true"></i><?php esc_html_e('登录', 'aksrt'); ?></a>
|
||||
<?php if (get_option('users_can_register')) :
|
||||
$register_url = function_exists('aksrt_get_register_url') ? aksrt_get_register_url() : wp_registration_url();
|
||||
?>
|
||||
@@ -508,7 +508,7 @@ if (!function_exists('aksrt_comments_render_form')) :
|
||||
$req_mark = $require_name_email ? '(' . __('必填', 'aksrt') . ')' : '';
|
||||
?>
|
||||
<span class="dropup relative" id="comment-user-info"<?php echo $require_name_email ? ' require_name_email="true"' : ''; ?>>
|
||||
<a class="but mr6" data-toggle-class="open" data-target="#comment-user-info" href="javascript:;"><i class="fa fa-fw fa-user" aria-hidden="true"></i><span class="hide-sm"><?php esc_html_e('昵称', 'aksrt'); ?></span></a>
|
||||
<a class="but mr6" data-toggle-class="open" data-target="#comment-user-info" href="javascript:;"><i class="fa fas fa-fw fa-user" aria-hidden="true"></i><span class="hide-sm"><?php esc_html_e('昵称', 'aksrt'); ?></span></a>
|
||||
<div class="dropdown-menu box-body" style="width:250px;">
|
||||
<div class="mb20">
|
||||
<p><?php esc_html_e('请填写用户信息:', 'aksrt'); ?></p>
|
||||
@@ -516,20 +516,20 @@ if (!function_exists('aksrt_comments_render_form')) :
|
||||
<li class="line-form mb10">
|
||||
<input type="text" name="author" class="line-form-input" tabindex="1" value="<?php echo esc_attr($comment_author); ?>" placeholder="">
|
||||
<div class="scale-placeholder"><?php echo esc_html__('昵称', 'aksrt') . esc_html($req_mark); ?></div>
|
||||
<div class="abs-right muted-color"><i class="fa fa-fw fa-user" aria-hidden="true"></i></div>
|
||||
<div class="abs-right muted-color"><i class="fa fas fa-fw fa-user" aria-hidden="true"></i></div>
|
||||
<i class="line-form-line"></i>
|
||||
</li>
|
||||
<li class="line-form">
|
||||
<input type="text" name="email" class="line-form-input" tabindex="2" value="<?php echo esc_attr($comment_email); ?>" placeholder="">
|
||||
<div class="scale-placeholder"><?php echo esc_html__('邮箱', 'aksrt') . esc_html($req_mark); ?></div>
|
||||
<div class="abs-right muted-color"><i class="fa fa-fw fa-envelope-o" aria-hidden="true"></i></div>
|
||||
<div class="abs-right muted-color"><i class="fa far fa-fw fa-envelope" aria-hidden="true"></i></div>
|
||||
<i class="line-form-line"></i>
|
||||
</li>
|
||||
<?php if (!empty($ctx['user_url_enabled'])) : ?>
|
||||
<li class="line-form">
|
||||
<input type="text" name="url" class="line-form-input" tabindex="3" value="<?php echo esc_attr($comment_author_url); ?>" placeholder="">
|
||||
<div class="scale-placeholder"><?php esc_html_e('博客地址', 'aksrt'); ?></div>
|
||||
<div class="abs-right muted-color"><i class="fa fa-fw fa-link" aria-hidden="true"></i></div>
|
||||
<div class="abs-right muted-color"><i class="fa fas fa-fw fa-link" aria-hidden="true"></i></div>
|
||||
<i class="line-form-line"></i>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
|
||||
@@ -328,7 +328,7 @@ if (!function_exists('aksrt_get_user_badges')) {
|
||||
$html .= '<a class="but c-blue tag-posts" data-toggle="tooltip" title="' . esc_attr(sprintf(__('共%s篇文章', 'aksrt'), $post_n)) . '" href="' . esc_url($home) . '">' . aksrt_renderer_svg_icon('post') . $post_n . '</a>';
|
||||
$html .= '<a class="but c-green tag-comment" data-toggle="tooltip" title="' . esc_attr(sprintf(__('共%s条评论', 'aksrt'), $com_n)) . '" href="' . esc_url($home) . '">' . aksrt_renderer_svg_icon('comment') . $com_n . '</a>';
|
||||
if ($followed_n) {
|
||||
$html .= '<a class="but c-yellow tag-follow" data-toggle="tooltip" title="' . esc_attr(sprintf(__('共%s个粉丝', 'aksrt'), $followed_n)) . '" href="' . esc_url($home) . '"><i class="fa fa-heart em09" aria-hidden="true"></i>' . $followed_n . '</a>';
|
||||
$html .= '<a class="but c-yellow tag-follow" data-toggle="tooltip" title="' . esc_attr(sprintf(__('共%s个粉丝', 'aksrt'), $followed_n)) . '" href="' . esc_url($home) . '"><i class="fa fas fa-heart em09" aria-hidden="true"></i>' . $followed_n . '</a>';
|
||||
} elseif ($like_n) {
|
||||
$html .= '<span class="badg c-yellow tag-like" data-toggle="tooltip" title="' . esc_attr(sprintf(__('获得%s个点赞', 'aksrt'), $like_n)) . '">' . aksrt_renderer_svg_icon('like') . $like_n . '</span>';
|
||||
}
|
||||
|
||||
+17
-17
@@ -1344,18 +1344,18 @@ if (!function_exists('aksrt_get_paywall_html')) {
|
||||
: __('开通会员', 'aksrt');
|
||||
$action_class = is_user_logged_in() ? 'pay-vip' : 'signin-loader';
|
||||
$icon = aksrt_get_pay_vip_icon_html($level_settings);
|
||||
$button = '<div class="badg c-yellow em09 mb6"><i class="fa fa-fw fa-info-circle mr6" aria-hidden="true"></i>' . esc_html(sprintf(__('您暂无购买权限,请先%s', 'aksrt'), $vip_action)) . '</div>';
|
||||
$button = '<div class="badg c-yellow em09 mb6"><i class="fa fas fa-fw fa-info-circle mr6" aria-hidden="true"></i>' . esc_html(sprintf(__('您暂无购买权限,请先%s', 'aksrt'), $vip_action)) . '</div>';
|
||||
$button .= '<a href="javascript:;" vip-level="' . esc_attr((string) $pay_limit) . '" data-vip-level="' . esc_attr((string) $pay_limit) . '" class="but btn-block jb-vip' . esc_attr((string) $pay_limit) . ' ' . esc_attr($action_class) . ' padding-lg">' . $icon . esc_html($vip_action) . '</a>';
|
||||
} elseif (!is_user_logged_in()) {
|
||||
if ($amount_minor > 0 && $modo === '0' && aksrt_allow_guest_content_pay($post)) {
|
||||
$button = '<button type="button" class="but jb-red padding-lg cashier-link' . $block_class . '" data-aksrt-pay-content="' . esc_attr((string) $post->ID) . '"><i class="fa fa-shopping-cart" aria-hidden="true"></i> ' . esc_html__('立即购买', 'aksrt') . '</button>';
|
||||
$button = '<button type="button" class="but jb-red padding-lg cashier-link' . $block_class . '" data-aksrt-pay-content="' . esc_attr((string) $post->ID) . '"><i class="fa fas fa-shopping-cart" aria-hidden="true"></i> ' . esc_html__('立即购买', 'aksrt') . '</button>';
|
||||
} else {
|
||||
$button = '<a href="javascript:;" class="but jb-blue signin-loader padding-lg' . $block_class . '"><i class="fa fa-sign-in mr10" aria-hidden="true"></i>' . esc_html__('登录购买', 'aksrt') . '</a>';
|
||||
$button = '<a href="javascript:;" class="but jb-blue signin-loader padding-lg' . $block_class . '"><i class="fa fas fa-sign-in-alt mr10" aria-hidden="true"></i>' . esc_html__('登录购买', 'aksrt') . '</a>';
|
||||
}
|
||||
} elseif ($amount_minor > 0) {
|
||||
$button = '<button type="button" class="but ' . ($modo === 'points' ? 'jb-yellow' : 'jb-red') . ' padding-lg cashier-link' . $block_class . '" data-aksrt-pay-content="' . esc_attr((string) $post->ID) . '"><i class="fa fa-shopping-cart" aria-hidden="true"></i> ' . esc_html__('立即购买', 'aksrt') . '</button>';
|
||||
$button = '<button type="button" class="but ' . ($modo === 'points' ? 'jb-yellow' : 'jb-red') . ' padding-lg cashier-link' . $block_class . '" data-aksrt-pay-content="' . esc_attr((string) $post->ID) . '"><i class="fa fas fa-shopping-cart" aria-hidden="true"></i> ' . esc_html__('立即购买', 'aksrt') . '</button>';
|
||||
} else {
|
||||
$button = '<button type="button" class="but jb-blue padding-lg cashier-link' . $block_class . '" data-aksrt-pay-content="' . esc_attr((string) $post->ID) . '"><i class="fa fa-eye" aria-hidden="true"></i> ' . esc_html__('查看内容', 'aksrt') . '</button>';
|
||||
$button = '<button type="button" class="but jb-blue padding-lg cashier-link' . $block_class . '" data-aksrt-pay-content="' . esc_attr((string) $post->ID) . '"><i class="fa fas fa-eye" aria-hidden="true"></i> ' . esc_html__('查看内容', 'aksrt') . '</button>';
|
||||
}
|
||||
$price = aksrt_get_show_pay_price_html($meta, $priced);
|
||||
$vip = aksrt_get_posts_vip_price($meta);
|
||||
@@ -1374,12 +1374,12 @@ if (!function_exists('aksrt_get_paywall_html')) {
|
||||
|
||||
if ($is_widget && aksrt_has_paid_access($post)) {
|
||||
$view_labels = [
|
||||
AKSRT_PAY_TYPE_DOWNLOAD => '<i class="fa fa-download fa-fw" aria-hidden="true"></i>' . esc_html__('获取下载地址', 'aksrt'),
|
||||
AKSRT_PAY_TYPE_GALLERY => '<i class="fa fa-file-image-o fa-fw" aria-hidden="true"></i>' . esc_html__('查看图片', 'aksrt'),
|
||||
AKSRT_PAY_TYPE_VIDEO => '<i class="fa fa-play-circle fa-fw" aria-hidden="true"></i>' . esc_html__('查看视频', 'aksrt'),
|
||||
AKSRT_PAY_TYPE_DOWNLOAD => '<i class="fa fas fa-download fa-fw" aria-hidden="true"></i>' . esc_html__('获取下载地址', 'aksrt'),
|
||||
AKSRT_PAY_TYPE_GALLERY => '<i class="fa far fa-file-image fa-fw" aria-hidden="true"></i>' . esc_html__('查看图片', 'aksrt'),
|
||||
AKSRT_PAY_TYPE_VIDEO => '<i class="fa fas fa-play-circle fa-fw" aria-hidden="true"></i>' . esc_html__('查看视频', 'aksrt'),
|
||||
];
|
||||
$view_label = $view_labels[$pay_type] ?? '<i class="fa fa-dot-circle-o fa-fw" aria-hidden="true"></i>' . esc_html__('查看内容', 'aksrt');
|
||||
return '<div class="zib-widget pay-box pay-widget paid-box order-type-' . $order_type . '" style="padding:0">' . $tag . '<div class="relative-h ' . esc_attr($theme) . '" style="background-size:120%"><div class="pay-widget__orb pay-widget__orb--right ' . esc_attr($theme) . '"></div><div class="pay-widget__orb pay-widget__orb--left ' . esc_attr($theme) . '"></div><div class="relative box-body"><div class="text-center mt10 box-body"><p><i class="fa fa-shopping-bag fa-3x" aria-hidden="true"></i></p><b class="em14">' . esc_html__('已购买', 'aksrt') . '</b></div></div></div><div class="box-body">' . $widget_service . '<div class="mt10"><a href="#posts-pay" class="but padding-lg btn-block ' . esc_attr($theme) . '">' . $view_label . '</a></div>' . $demo_row . $attrs . '</div>' . $count . '</div>';
|
||||
$view_label = $view_labels[$pay_type] ?? '<i class="fa far fa-dot-circle fa-fw" aria-hidden="true"></i>' . esc_html__('查看内容', 'aksrt');
|
||||
return '<div class="zib-widget pay-box pay-widget paid-box order-type-' . $order_type . '" style="padding:0">' . $tag . '<div class="relative-h ' . esc_attr($theme) . '" style="background-size:120%"><div class="pay-widget__orb pay-widget__orb--right ' . esc_attr($theme) . '"></div><div class="pay-widget__orb pay-widget__orb--left ' . esc_attr($theme) . '"></div><div class="relative box-body"><div class="text-center mt10 box-body"><p><i class="fa fas fa-shopping-bag fa-3x" aria-hidden="true"></i></p><b class="em14">' . esc_html__('已购买', 'aksrt') . '</b></div></div></div><div class="box-body">' . $widget_service . '<div class="mt10"><a href="#posts-pay" class="but padding-lg btn-block ' . esc_attr($theme) . '">' . $view_label . '</a></div>' . $demo_row . $attrs . '</div>' . $count . '</div>';
|
||||
}
|
||||
|
||||
if ($is_widget) {
|
||||
@@ -1388,7 +1388,7 @@ if (!function_exists('aksrt_get_paywall_html')) {
|
||||
|
||||
$thumb = get_the_post_thumbnail($post, 'medium', ['class' => 'fit-cover', 'alt' => '']);
|
||||
if ($thumb === '') {
|
||||
$thumb = '<div class="pay-thumb-placeholder"><i class="fa fa-lock" aria-hidden="true"></i></div>';
|
||||
$thumb = '<div class="pay-thumb-placeholder"><i class="fa fas fa-lock" aria-hidden="true"></i></div>';
|
||||
}
|
||||
$graphic_actions = '';
|
||||
if ($demo !== '' || $discount_text !== '') {
|
||||
@@ -1402,7 +1402,7 @@ if (!function_exists('aksrt_get_paywall_html')) {
|
||||
$gallery_count = count((array) ($meta['gallery'] ?? []));
|
||||
$graphic = '<div class="flex0 relative mr20 hide-sm pay-thumb"><div class="graphic"><div class="blur-10 absolute">' . $thumb . '</div><div class="absolute graphic-mask" style="opacity:.3"></div><div class="abs-center text-center">' . esc_html(sprintf(__('共%s张图片', 'aksrt'), $gallery_count)) . '<br>' . esc_html__('请付费后查看', 'aksrt') . '</div>' . $graphic_actions . '</div></div>';
|
||||
} elseif ($pay_type === AKSRT_PAY_TYPE_VIDEO) {
|
||||
$graphic = '<div class="flex0 relative mr20 hide-sm pay-thumb"><div class="graphic">' . $thumb . '<div class="absolute graphic-mask" style="opacity:.2"></div><div class="abs-center text-center"><i class="fa fa-play-circle-o fa-4x opacity8" aria-hidden="true"></i></div>' . $graphic_actions . '</div></div>';
|
||||
$graphic = '<div class="flex0 relative mr20 hide-sm pay-thumb"><div class="graphic">' . $thumb . '<div class="absolute graphic-mask" style="opacity:.2"></div><div class="abs-center text-center"><i class="fa far fa-play-circle fa-4x opacity8" aria-hidden="true"></i></div>' . $graphic_actions . '</div></div>';
|
||||
} else {
|
||||
$graphic = '<div class="flex0 relative mr20 hide-sm pay-thumb"><div class="graphic">' . $thumb . $graphic_actions . '</div></div>';
|
||||
}
|
||||
@@ -1471,10 +1471,10 @@ if (!function_exists('aksrt_get_paid_download_actions_html')) {
|
||||
$buttons .= '<div class="but-download flex ac">';
|
||||
if ($direct_download) {
|
||||
$buttons .= '<a class="mr10 but ' . esc_attr($button_class) . '" href="' . esc_url($url) . '" target="_blank" rel="nofollow noopener">';
|
||||
$buttons .= '<i class="fa fa-download" aria-hidden="true"></i>' . esc_html($label) . '</a>';
|
||||
$buttons .= '<i class="fa fas fa-download" aria-hidden="true"></i>' . esc_html($label) . '</a>';
|
||||
} else {
|
||||
$buttons .= '<button type="button" class="mr10 but ' . esc_attr($button_class) . '" data-action="aksrt-download" data-source-index="' . esc_attr((string) $index) . '" data-source-type="' . esc_attr($type) . '" data-has-extract="' . ($has_extract ? '1' : '0') . '">';
|
||||
$buttons .= '<i class="fa fa-download" aria-hidden="true"></i>' . esc_html($label) . '</button>';
|
||||
$buttons .= '<i class="fa fas fa-download" aria-hidden="true"></i>' . esc_html($label) . '</button>';
|
||||
}
|
||||
if ($copy_value !== '') {
|
||||
$buttons .= '<button type="button" class="but" data-clipboard-tag="' . esc_attr($copy_key !== '' ? $copy_key : __('内容', 'aksrt')) . '" data-clipboard-text="' . esc_attr($copy_value) . '">' . esc_html($copy_label) . '</button>';
|
||||
@@ -1552,12 +1552,12 @@ if (!function_exists('aksrt_get_paid_box_html')) {
|
||||
$paid_info .= '<div class="flex jsb"><span>' . esc_html__('支付时间', 'aksrt') . '</span><span>' . esc_html($paid_at) . '</span></div>';
|
||||
}
|
||||
$paid_info .= '<div class="flex jsb"><span>' . esc_html__('支付金额', 'aksrt') . '</span><span>' . esc_html($amount_text) . '</span></div>';
|
||||
$paid_box = '<div class="flex ac jb-green padding-10 em09"><div class="text-center flex-auto"><div class="mb6"><i class="fa fa-shopping-bag fa-2x" aria-hidden="true"></i></div><b class="em12">' . esc_html__('已购买', 'aksrt') . '</b></div><div class="em09 paid-info flex-auto">' . $paid_info . '</div></div>';
|
||||
$paid_box = '<div class="flex ac jb-green padding-10 em09"><div class="text-center flex-auto"><div class="mb6"><i class="fa fas fa-shopping-bag fa-2x" aria-hidden="true"></i></div><b class="em12">' . esc_html__('已购买', 'aksrt') . '</b></div><div class="em09 paid-info flex-auto">' . $paid_info . '</div></div>';
|
||||
} elseif ($vip_level > 0 || $pay_type === AKSRT_PAY_TYPE_VIP) {
|
||||
$level = max(1, $vip_level);
|
||||
$price_label = aksrt_get_pay_price_label($post);
|
||||
$price = '<div class="price-box"><div class="text-center"><b class="em3x">' . esc_html((string) ($price_label['text'] ?? '')) . '</b></div></div>';
|
||||
$paid_box = '<div class="flex jsb ac payvip-icon box-body vipbg-v' . esc_attr((string) $level) . '">' . $price . '<div class="flex0"><b class="em12"><i class="fa fa-certificate mr10 em12" aria-hidden="true"></i>' . esc_html(sprintf(__('VIP%d 会员免费', 'aksrt'), $level)) . '</b></div></div>';
|
||||
$paid_box = '<div class="flex jsb ac payvip-icon box-body vipbg-v' . esc_attr((string) $level) . '">' . $price . '<div class="flex0"><b class="em12"><i class="fa fas fa-certificate mr10 em12" aria-hidden="true"></i>' . esc_html(sprintf(__('VIP%d 会员免费', 'aksrt'), $level)) . '</b></div></div>';
|
||||
} else {
|
||||
$type_label = str_replace(__('付费', 'aksrt'), __('免费', 'aksrt'), $type_label);
|
||||
}
|
||||
@@ -1574,7 +1574,7 @@ if (!function_exists('aksrt_get_paid_box_html')) {
|
||||
if ($pay_type === AKSRT_PAY_TYPE_DOWNLOAD) {
|
||||
$captcha_active = function_exists('aksrt_is_captcha_enabled_for') && aksrt_is_captcha_enabled_for('download');
|
||||
$root_data = ' data-aksrt-download-box data-post-id="' . esc_attr((string) $post->ID) . '" data-captcha="' . ($captcha_active ? '1' : '0') . '"';
|
||||
$download_box = '<div class="hidden-box show"><div class="hidden-text"><i class="fa fa-download mr6" aria-hidden="true"></i>' . esc_html__('资源下载', 'aksrt') . '</div>' . aksrt_get_paid_download_actions_html($meta) . '</div>';
|
||||
$download_box = '<div class="hidden-box show"><div class="hidden-text"><i class="fa fas fa-download mr6" aria-hidden="true"></i>' . esc_html__('资源下载', 'aksrt') . '</div>' . aksrt_get_paid_download_actions_html($meta) . '</div>';
|
||||
$demo = aksrt_get_demo_link_html($post, 'but jb-yellow padding-lg');
|
||||
if ($demo !== '') {
|
||||
$download_box .= '<div class="mt10">' . $demo . '</div>';
|
||||
|
||||
@@ -50,7 +50,7 @@ if (!function_exists('aksrt_get_input_expand_but')) :
|
||||
|
||||
switch ($type) {
|
||||
case 'link':
|
||||
$but = '<a class="but btn-input-expand input-link mr6" href="javascript:;"><i class="fa fa-fw fa-link" aria-hidden="true"></i><span class="hide-sm">' . esc_html__('链接', 'aksrt') . '</span></a>';
|
||||
$but = '<a class="but btn-input-expand input-link mr6" href="javascript:;"><i class="fa fas fa-fw fa-link" aria-hidden="true"></i><span class="hide-sm">' . esc_html__('链接', 'aksrt') . '</span></a>';
|
||||
$dropdown = '<div class="dropdown-link">';
|
||||
$dropdown .= '<p>' . esc_html__('请输入链接:', 'aksrt') . '</p>';
|
||||
$dropdown .= '<p><textarea rows="2" tabindex="1" class="form-control input-textarea link-textarea" style="height:55px;" placeholder="https://..."></textarea></p>';
|
||||
@@ -60,7 +60,7 @@ if (!function_exists('aksrt_get_input_expand_but')) :
|
||||
break;
|
||||
|
||||
case 'code':
|
||||
$but = '<a class="but btn-input-expand input-code mr6" href="javascript:;"><i class="fa fa-fw fa-code" aria-hidden="true"></i><span class="hide-sm">' . esc_html__('代码', 'aksrt') . '</span></a>';
|
||||
$but = '<a class="but btn-input-expand input-code mr6" href="javascript:;"><i class="fa fas fa-fw fa-code" aria-hidden="true"></i><span class="hide-sm">' . esc_html__('代码', 'aksrt') . '</span></a>';
|
||||
$dropdown = '<div class="dropdown-code">';
|
||||
$dropdown .= '<p>' . esc_html__('请输入代码:', 'aksrt') . '</p>';
|
||||
$dropdown .= '<p><textarea rows="6" tabindex="1" class="form-control input-textarea" placeholder="' . esc_attr__('在此处粘贴或输入代码', 'aksrt') . '"></textarea></p>';
|
||||
@@ -70,7 +70,7 @@ if (!function_exists('aksrt_get_input_expand_but')) :
|
||||
|
||||
case 'image':
|
||||
$upload = !empty($arg1) || !empty($ctx['upload']);
|
||||
$but = '<a class="but btn-input-expand input-image mr6" href="javascript:;"><i class="fa fa-fw fa-image" aria-hidden="true"></i><span class="hide-sm">' . esc_html__('图片', 'aksrt') . '</span></a>';
|
||||
$but = '<a class="but btn-input-expand input-image mr6" href="javascript:;"><i class="fa fas fa-fw fa-image" aria-hidden="true"></i><span class="hide-sm">' . esc_html__('图片', 'aksrt') . '</span></a>';
|
||||
|
||||
$dropdown = '<div class="dropdown-image">';
|
||||
$dropdown .= '<p>' . esc_html__('请填写图片地址:', 'aksrt') . '</p>';
|
||||
|
||||
@@ -163,10 +163,10 @@ if (!function_exists('aksrt_get_comments_action_dropdown_html')) :
|
||||
$label = $is_pinned ? __('取消置顶', 'aksrt') : __('设置置顶', 'aksrt');
|
||||
// 不带 legacy 的 wp-ajax-submit 类:vendor main.min.js 会全局代理该类并向
|
||||
// admin-ajax 发空 action 请求(400 "0"),置顶走 data-comment-action REST。
|
||||
$lists .= '<li><a class="comment-topping" data-comment-action="pin" data-pinned="' . ($is_pinned ? '1' : '0') . '" href="javascript:;"><i class="fa fa-thumbtack mr10 fa-fw" aria-hidden="true"></i>' . esc_html($label) . '</a></li>';
|
||||
$lists .= '<li><a class="comment-topping" data-comment-action="pin" data-pinned="' . ($is_pinned ? '1' : '0') . '" href="javascript:;"><i class="fa fas fa-thumbtack mr10 fa-fw" aria-hidden="true"></i>' . esc_html($label) . '</a></li>';
|
||||
}
|
||||
if (!empty($perms['can_edit'])) {
|
||||
$lists .= '<li><a class="comment-edit-link" data-commentid="' . (int) $comment->comment_ID . '" data-postid="' . (int) $comment->comment_post_ID . '" href="javascript:;"><i class="fa fa-edit mr10 fa-fw" aria-hidden="true"></i>' . esc_html__('编辑', 'aksrt') . '</a></li>';
|
||||
$lists .= '<li><a class="comment-edit-link" data-commentid="' . (int) $comment->comment_ID . '" data-postid="' . (int) $comment->comment_post_ID . '" href="javascript:;"><i class="fa fas fa-edit mr10 fa-fw" aria-hidden="true"></i>' . esc_html__('编辑', 'aksrt') . '</a></li>';
|
||||
}
|
||||
if (!empty($perms['can_moderate'])) {
|
||||
$text = $is_pending ? __('批准', 'aksrt') : __('驳回', 'aksrt');
|
||||
@@ -176,7 +176,7 @@ if (!function_exists('aksrt_get_comments_action_dropdown_html')) :
|
||||
$lists .= '<li><a class="comment-approve-link ' . $class . '" data-comment-action="' . $action . '" data-commentid="' . (int) $comment->comment_ID . '" data-postid="' . (int) $comment->comment_post_ID . '" href="javascript:;">' . $approve_icon . '<text>' . esc_html($text) . '</text></a></li>';
|
||||
}
|
||||
if (!empty($perms['can_delete'])) {
|
||||
$lists .= '<li><a class="comment-trash-link c-red" data-comment-action="delete" data-commentid="' . (int) $comment->comment_ID . '" data-postid="' . (int) $comment->comment_post_ID . '" href="javascript:;"><i class="fa fa-trash-o mr10 fa-fw" aria-hidden="true"></i>' . esc_html__('删除', 'aksrt') . '</a></li>';
|
||||
$lists .= '<li><a class="comment-trash-link c-red" data-comment-action="delete" data-commentid="' . (int) $comment->comment_ID . '" data-postid="' . (int) $comment->comment_post_ID . '" href="javascript:;"><i class="fa far fa-trash-alt mr10 fa-fw" aria-hidden="true"></i>' . esc_html__('删除', 'aksrt') . '</a></li>';
|
||||
}
|
||||
|
||||
if ($lists === '') {
|
||||
|
||||
@@ -588,8 +588,8 @@ if (!function_exists('aksrt_render_comment_pagination')) {
|
||||
'base' => $base,
|
||||
'type' => 'array',
|
||||
'mid_size' => $is_mobile ? 1 : 2,
|
||||
'prev_text' => '<i class="fa fa-angle-left em12"></i><span class="hide-sm ml6">' . __('上一页', 'aksrt') . '</span>',
|
||||
'next_text' => '<span class="hide-sm mr6">' . __('下一页', 'aksrt') . '</span><i class="fa fa-angle-right em12"></i>',
|
||||
'prev_text' => '<i class="fa fas fa-angle-left em12"></i><span class="hide-sm ml6">' . __('上一页', 'aksrt') . '</span>',
|
||||
'next_text' => '<span class="hide-sm mr6">' . __('下一页', 'aksrt') . '</span><i class="fa fas fa-angle-right em12"></i>',
|
||||
'total' => $max_pages,
|
||||
'current' => $paged,
|
||||
'add_fragment' => '#comments',
|
||||
@@ -601,7 +601,7 @@ if (!function_exists('aksrt_render_comment_pagination')) {
|
||||
}
|
||||
|
||||
if ($max_pages > 8) {
|
||||
$array[] = '<a class="pag-jump page-numbers" href="javascript:;" no-scroll="true" data-jump-comments="1"><input autocomplete="off" max="' . esc_attr((string) $max_pages) . '" current="' . esc_attr((string) $paged) . '" type="' . ($is_mobile ? 'number' : 'text') . '" class="form-control jump-input" name="pag-go"><span class="hide-sm mr6 jump-text">' . __('跳转', 'aksrt') . '</span><i class="jump-icon fa fa-angle-double-right em12"></i></a>';
|
||||
$array[] = '<a class="pag-jump page-numbers" href="javascript:;" no-scroll="true" data-jump-comments="1"><input autocomplete="off" max="' . esc_attr((string) $max_pages) . '" current="' . esc_attr((string) $paged) . '" type="' . ($is_mobile ? 'number' : 'text') . '" class="form-control jump-input" name="pag-go"><span class="hide-sm mr6 jump-text">' . __('跳转', 'aksrt') . '</span><i class="jump-icon fa fas fa-angle-double-right em12"></i></a>';
|
||||
}
|
||||
|
||||
echo '<div class="pagenav" data-current-page="' . esc_attr((string) $paged) . '" data-max-pages="' . esc_attr((string) $max_pages) . '">';
|
||||
|
||||
@@ -53,7 +53,7 @@ class SchemaPageDisplay {
|
||||
self::field('nav_newposts', 'Add发布按钮', 'switcher', true, ['description' => '顶部导航显示文章投稿按钮。']),
|
||||
self::field('nav_newposts_radius', '按钮圆角', 'switcher', true, ['dependsOn' => self::enabled('nav_newposts')]),
|
||||
self::field('nav_newposts_class', '按钮颜色', 'palette', 'jb-blue', ['dependsOn' => self::enabled('nav_newposts'), 'options' => self::aksrt_palette()]),
|
||||
self::field('nav_newposts_text', '按钮文案', 'textarea', '<i class="fa fa-fw fa-pencil"></i>发布', ['dependsOn' => self::enabled('nav_newposts'), 'sanitize_type' => 'html', 'rows' => 1]),
|
||||
self::field('nav_newposts_text', '按钮文案', 'textarea', '<i class="fa fas fa-fw fas fa-pencil-alt"></i>发布', ['dependsOn' => self::enabled('nav_newposts'), 'sanitize_type' => 'html', 'rows' => 1]),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ class SchemaPageDisplay {
|
||||
self::field('footer_contact_weibo', '微博链接', 'url', 'https://weibo.com/'),
|
||||
self::field('footer_contact_email', '邮箱', 'text', '1234567788@QQ.COM'),
|
||||
self::field('footer_contact_more', '更多图标联系方式', 'group', [], ['button_title' => '添加图标联系方式', 'fields' => [
|
||||
self::field('desc', '按钮名称', 'text', ''), self::field('icon', '按钮图标', 'icon', 'fa fa-heart'), self::field('link', '按钮链接', 'url', '', ['dependsOn' => ['key' => 'img', 'operator' => 'empty']]), self::field('img', '二维码图片', 'upload', ''),
|
||||
self::field('desc', '按钮名称', 'text', ''), self::field('icon', '按钮图标', 'icon', 'fa fas fa-heart'), self::field('link', '按钮链接', 'url', '', ['dependsOn' => ['key' => 'img', 'operator' => 'empty']]), self::field('img', '二维码图片', 'upload', ''),
|
||||
]]),
|
||||
self::field('footer_mini_img_m_s', '版块三移动端显示', 'switcher', true),
|
||||
self::field('footer_mini_img', '版块三大图片', 'group', [['image' => $img . 'qrcode.png', 'text' => '扫码加QQ群'], ['image' => $img . 'qrcode.png', 'text' => '扫码加微信']], ['max' => 4, 'button_title' => '添加图片', 'fields' => self::footer_image_fields()]),
|
||||
@@ -181,7 +181,7 @@ class SchemaPageDisplay {
|
||||
}
|
||||
|
||||
private static function card_fields(): array {
|
||||
return [self::field('icon_radius4', '方形图标', 'switcher', false), self::field('cards', '添加卡片', 'group', [], ['button_title' => '添加内容', 'fields' => [self::field('title', '文案标题', 'textarea', '', ['sanitize_type' => 'html']), self::field('desc', '文案简介', 'textarea', '', ['sanitize_type' => 'html']), self::field('icon', '选择图标', 'icon', 'fa fa-magic'), self::field('customize_icon', '自定义图标', 'textarea', '', ['sanitize_type' => 'html']), self::field('icon_class', '图标颜色', 'palette', 'c-yellow', ['options' => self::aksrt_palette(true)]), self::field('link', '跳转链接', 'link', [])]])];
|
||||
return [self::field('icon_radius4', '方形图标', 'switcher', false), self::field('cards', '添加卡片', 'group', [], ['button_title' => '添加内容', 'fields' => [self::field('title', '文案标题', 'textarea', '', ['sanitize_type' => 'html']), self::field('desc', '文案简介', 'textarea', '', ['sanitize_type' => 'html']), self::field('icon', '选择图标', 'icon', 'fa fas fa-magic'), self::field('customize_icon', '自定义图标', 'textarea', '', ['sanitize_type' => 'html']), self::field('icon_class', '图标颜色', 'palette', 'c-yellow', ['options' => self::aksrt_palette(true)]), self::field('link', '跳转链接', 'link', [])]])];
|
||||
}
|
||||
|
||||
private static function orderby_fields(): array { return [self::field('lists', '显示排序方式', 'select', ['modified', 'views', 'like', 'comment_count'], ['multiple' => true, 'sortable' => true, 'options' => self::post_order_options(false)]), self::field('dropdown', '更多排序方式', 'switcher', false)]; }
|
||||
@@ -190,7 +190,7 @@ class SchemaPageDisplay {
|
||||
private static function header_slider_defaults(): array { $img = self::asset('assets/img/'); return [['background' => $img . 'slider-bg.jpg', 'link' => ['url' => home_url('/'), 'target' => '_blank'], 'text' => ['title' => '', 'desc' => ''], 'text_align' => 'left-bottom', 'text_parallax' => 30, 'text_size_m' => 20, 'text_size_pc' => 30], ['background' => $img . 'user_t.jpg', 'link' => ['url' => home_url('/'), 'target' => '_blank'], 'text' => ['title' => '', 'desc' => ''], 'text_align' => 'left-bottom', 'text_parallax' => 30, 'text_size_m' => 20, 'text_size_pc' => 30]]; }
|
||||
private static function slider_options_defaults(): array { return ['direction' => 'horizontal', 'loop' => true, 'button' => true, 'pagination' => true, 'effect' => 'slide', 'scale_height' => false, 'auto_height' => false, 'pc_height' => 550, 'm_height' => 280, 'spacebetween' => 0, 'speed' => 0, 'autoplay' => true, 'interval' => 6]; }
|
||||
private static function search_defaults(): array { return ['show_keywords' => true, 'popular_limit' => 6, 'show_input_cat' => false, 'in_cat' => '', 'more_cats' => '', 'show_type' => false, 'in_type' => 'post', 'before_html' => '<div class="em16 font-bold mb10">更优雅的Wordpress主题</div>' . "\n" . '<div>这是导航栏幻灯片多功能组件,可在后台进行配置</div>', 'after_html' => '']; }
|
||||
private static function card_defaults(): array { return ['icon_radius4' => false, 'cards' => [['icon' => 'fa fas fa-gem', 'customize_icon' => '', 'icon_class' => 'c-yellow', 'link' => [], 'title' => '图标卡片', 'desc' => '这是一个图标卡片示例'], ['icon' => 'fa fas fa-star', 'customize_icon' => '', 'icon_class' => 'c-blue-2', 'link' => [], 'title' => '原创作品', 'desc' => '这是一个图标卡片示例'], ['icon' => 'fa fas fa-fire', 'customize_icon' => '', 'icon_class' => 'jb-pink', 'link' => [], 'title' => '灵感来源<badge class="ml6 jb-yellow">NEW</badge>', 'desc' => '这是一个图标卡片示例'], ['icon' => 'fa fas fa-wrench', 'customize_icon' => '', 'icon_class' => 'jb-cyan', 'link' => [], 'title' => '系统工具 <badge class="ml6 jb-blue">GO <span class="fa fa-angle-right em12"></span></badge>', 'desc' => '这是一个图标卡片示例']]]; }
|
||||
private static function card_defaults(): array { return ['icon_radius4' => false, 'cards' => [['icon' => 'fa fas fa-gem', 'customize_icon' => '', 'icon_class' => 'c-yellow', 'link' => [], 'title' => '图标卡片', 'desc' => '这是一个图标卡片示例'], ['icon' => 'fa fas fa-star', 'customize_icon' => '', 'icon_class' => 'c-blue-2', 'link' => [], 'title' => '原创作品', 'desc' => '这是一个图标卡片示例'], ['icon' => 'fa fas fa-fire', 'customize_icon' => '', 'icon_class' => 'jb-pink', 'link' => [], 'title' => '灵感来源<badge class="ml6 jb-yellow">NEW</badge>', 'desc' => '这是一个图标卡片示例'], ['icon' => 'fa fas fa-wrench', 'customize_icon' => '', 'icon_class' => 'jb-cyan', 'link' => [], 'title' => '系统工具 <badge class="ml6 jb-blue">GO <span class="fa fas fa-angle-right em12"></span></badge>', 'desc' => '这是一个图标卡片示例']]]; }
|
||||
|
||||
private static function field(string $key, string $label, string $type, $default = null, array $extra = []): array { return array_merge(['key' => $key, 'label' => $label, 'type' => $type, 'default' => $default], $extra); }
|
||||
private static function notice(string $content): array { return ['key' => '_notice_' . md5($content), 'type' => 'notice', 'content' => $content, 'tone' => 'warning']; }
|
||||
|
||||
@@ -172,7 +172,7 @@ trait VipServiceModal {
|
||||
$html .= $equity_html;
|
||||
$html .= '<a class="but jb-blue radius payvip-button" href="javascript:;">'
|
||||
. esc_html(sprintf(__('开通%s', 'aksrt'), $name))
|
||||
. '<span class="ml6"><i class="fa fa-chevron-circle-right" aria-hidden="true"></i></span></a>';
|
||||
. '<span class="ml6"><i class="fa fas fa-chevron-circle-right" aria-hidden="true"></i></span></a>';
|
||||
$html .= '</div></div>';
|
||||
return $html;
|
||||
}
|
||||
|
||||
@@ -469,7 +469,7 @@ trait ScriptsPart1b {
|
||||
wp_enqueue_script(
|
||||
'aksrt-section-navs',
|
||||
$base_uri . '/assets/js/section-navs.js',
|
||||
['jquery'],
|
||||
['aksrt-runtime'],
|
||||
(string) filemtime($section_navs),
|
||||
true
|
||||
);
|
||||
|
||||
@@ -232,7 +232,7 @@ final class UserRenderer {
|
||||
if ($url === '') {
|
||||
return '';
|
||||
}
|
||||
return '<a rel="nofollow" class="newadd-btns ' . esc_attr($class) . '" href="' . esc_url($url) . '"><icon class="jb-green"><i class="fa fas fa-pencil-square" aria-hidden="true"></i></icon><text>' . esc_html($text) . '</text></a>';
|
||||
return '<a rel="nofollow" class="newadd-btns ' . esc_attr($class) . '" href="' . esc_url($url) . '"><icon class="jb-green"><i class="fa fas fa-edit" aria-hidden="true"></i></icon><text>' . esc_html($text) . '</text></a>';
|
||||
}
|
||||
|
||||
private static function card_link(string $url, string $class, string $text, bool $nofollow = false): string {
|
||||
|
||||
@@ -392,7 +392,7 @@ final class WidgetSchemas {
|
||||
['id' => 'm_row', 'type' => 'button_set', 'label' => '移动端单行排列数量', 'default' => 2, 'options' => [1 => '1个', 2 => '2个', 3 => '3个', 4 => '4个', 6 => '6个', 12 => '12个']],
|
||||
['id' => 'size', 'type' => 'slider', 'label' => '图标尺寸微调', 'default' => 0, 'min' => -10, 'max' => 10, 'step' => 1],
|
||||
['id' => 'cards', 'type' => 'group', 'label' => '添加图标', 'max_items' => 40, 'default' => [], 'fields' => [
|
||||
['id' => 'icon', 'type' => 'icon', 'label' => '选择图标', 'default' => 'fa fa-magic'],
|
||||
['id' => 'icon', 'type' => 'icon', 'label' => '选择图标', 'default' => 'fa fas fa-magic'],
|
||||
['id' => 'customize_icon', 'type' => 'textarea', 'label' => '自定义图标', 'default' => '', 'allow_html' => true, 'attributes' => ['rows' => 1]],
|
||||
['id' => 'link', 'type' => 'link', 'label' => '跳转链接', 'default' => []],
|
||||
['id' => 'icon_radius', 'type' => 'switcher', 'label' => '显示图标背景', 'default' => false],
|
||||
@@ -414,7 +414,7 @@ final class WidgetSchemas {
|
||||
['id' => 'cards', 'type' => 'group', 'label' => '添加卡片', 'max_items' => 40, 'default' => [], 'fields' => [
|
||||
['id' => 'title', 'type' => 'textarea', 'label' => '文案标题', 'default' => '', 'allow_html' => true, 'attributes' => ['rows' => 1]],
|
||||
['id' => 'desc', 'type' => 'textarea', 'label' => '文案简介', 'default' => '', 'allow_html' => true, 'attributes' => ['rows' => 2]],
|
||||
['id' => 'icon', 'type' => 'icon', 'label' => '选择图标', 'default' => 'fa fa-magic'],
|
||||
['id' => 'icon', 'type' => 'icon', 'label' => '选择图标', 'default' => 'fa fas fa-magic'],
|
||||
['id' => 'customize_icon', 'type' => 'textarea', 'label' => '自定义图标', 'default' => '', 'allow_html' => true, 'attributes' => ['rows' => 1]],
|
||||
['id' => 'icon_class', 'type' => 'palette', 'label' => '图标颜色', 'default' => 'c-yellow', 'options' => self::icon_background_palette()],
|
||||
['id' => 'link', 'type' => 'link', 'label' => '跳转链接', 'default' => []],
|
||||
|
||||
@@ -58,7 +58,7 @@ if (file_exists($js)) {
|
||||
wp_enqueue_script(
|
||||
'aksrt-front-submit-pay-download',
|
||||
get_template_directory_uri() . '/assets/js/front-submit-pay-download.js',
|
||||
[],
|
||||
['aksrt-runtime'],
|
||||
(string) filemtime($pay_download_js),
|
||||
true
|
||||
);
|
||||
@@ -74,7 +74,7 @@ if (file_exists($js)) {
|
||||
wp_enqueue_script(
|
||||
'aksrt-mini-upload',
|
||||
get_template_directory_uri() . '/assets/js/mini-upload.js',
|
||||
[],
|
||||
['aksrt-runtime'],
|
||||
(string) filemtime($mini),
|
||||
true
|
||||
);
|
||||
|
||||
@@ -38,13 +38,19 @@ const header = join([
|
||||
]);
|
||||
|
||||
test('the public dependency graph is the single local runtime stack', () => {
|
||||
assert.match(scripts, /wp_deregister_script\('jquery'\)/);
|
||||
assert.match(scripts, /jquery\.min\.js'[\s\S]*?'1\.9\.1'/);
|
||||
assert.match(scripts, /bootstrap\.min\.css'[\s\S]*?'3\.4\.1'/);
|
||||
assert.match(scripts, /fontawesome5'[\s\S]*?all\.min\.css'[\s\S]*?'5\.15\.4'/);
|
||||
assert.match(scripts, /main\.min\.css/);
|
||||
assert.match(scripts, /loader\.js'[\s\S]*?\['jquery', 'bootstrap'\]/);
|
||||
assert.match(read('assets/js/runtime/loader.js'), /tbquire\(\['main'\]\)/);
|
||||
const buildTool = read('tools/build-public-assets.mjs');
|
||||
|
||||
assert.match(scripts, /registered\['jquery'\]->deps = \['jquery-core'\]/);
|
||||
assert.match(scripts, /wp_enqueue_script\('jquery'\)/);
|
||||
assert.doesNotMatch(scripts, /wp_deregister_script\('jquery'\)/);
|
||||
assert.match(scripts, /'aksrt-runtime'/);
|
||||
assert.match(scripts, /assets\/js\/build\/public\.js/);
|
||||
assert.match(buildTool, /assets\/css\/bootstrap\.min\.css/);
|
||||
assert.match(buildTool, /assets\/fontawesome5\/css\/all\.min\.css/);
|
||||
assert.match(buildTool, /assets\/css\/main\.min\.css/);
|
||||
assert.match(buildTool, /assets\/js\/runtime\/libs\/bootstrap\.min\.js/);
|
||||
assert.match(buildTool, /assets\/js\/runtime\/loader\.js/);
|
||||
assert.match(buildTool, /assets\/js\/runtime\/main\.min\.js/);
|
||||
for (const file of [
|
||||
'assets/js/runtime/libs/jquery.min.js',
|
||||
'assets/js/runtime/libs/bootstrap.min.js',
|
||||
@@ -146,16 +152,17 @@ test('mobile navigation is one setting-driven left right or top drawer', () => {
|
||||
|
||||
test('guest account member VIP and publish contracts share reference header DOM', () => {
|
||||
const userboxCss = read('assets/css/frontend/header-userbox.css');
|
||||
const buildTool = read('tools/build-public-assets.mjs');
|
||||
|
||||
assert.match(header, /is_user_logged_in\(\)/);
|
||||
assert.match(header, /sub-user-box aksrt-header-userbox/);
|
||||
assert.match(header, /signin-loader|signin/);
|
||||
assert.match(header, /get_payment_vip_settings/);
|
||||
assert.match(header, /nav_user_newposts_btn/);
|
||||
assert.match(header, /navbar-newposts/);
|
||||
assert.match(header, /nav_newposts/);
|
||||
assert.match(header, /navbar-form navbar-right navbar-but/);
|
||||
assert.match(header, /navbar-form navbar-right/);
|
||||
assert.match(header, /pay-vip/);
|
||||
assert.match(scripts, /\$enqueue_module\('header-userbox'\)/);
|
||||
assert.match(buildTool, /assets\/css\/frontend\/header-userbox\.css/);
|
||||
assert.match(userboxCss, /\.aksrt-header-userbox \.user-info > \.avatar/);
|
||||
assert.match(userboxCss, /\.aksrt-header-wallet/);
|
||||
assert.match(userboxCss, /\.aksrt-header-checkin/);
|
||||
|
||||
@@ -72,7 +72,11 @@ function createHarness() {
|
||||
});
|
||||
|
||||
let providerCallback;
|
||||
let captchaInit = null;
|
||||
const window = {
|
||||
AksrtFrontend: {
|
||||
register(_name, init) { captchaInit = init; },
|
||||
},
|
||||
fetch(url) {
|
||||
if (url === '/challenge') return Promise.resolve({ ok: true, json: () => Promise.resolve({ success: true, data: { challenge: 'challenge-token' } }) });
|
||||
if (url === '/exchange') return Promise.resolve({ ok: true, json: () => Promise.resolve({ success: true, data: { proof: 'proof-token' } }) });
|
||||
@@ -87,6 +91,7 @@ function createHarness() {
|
||||
Promise,
|
||||
};
|
||||
vm.runInNewContext(runtime, { window, document, Promise, MutationObserver: undefined, setTimeout, clearTimeout, console });
|
||||
if (captchaInit) captchaInit(document, 'init');
|
||||
return { api: window.AKSRTCaptcha, container };
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
'use strict';
|
||||
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const test = require('node:test');
|
||||
|
||||
const root = path.resolve(__dirname, '..', '..');
|
||||
const read = (file) => fs.readFileSync(path.join(root, file), 'utf8');
|
||||
|
||||
const publicSources = [
|
||||
'assets/js/core/comment-fixed-input.js',
|
||||
'assets/js/core/misc.js',
|
||||
'assets/js/follow.js',
|
||||
'assets/js/enhancements.js',
|
||||
'assets/js/enhancements2.js',
|
||||
'assets/js/color-extract.js',
|
||||
'assets/js/effects.js',
|
||||
'assets/js/captcha-front.js',
|
||||
'assets/widgets/frontend.js',
|
||||
];
|
||||
|
||||
const routedSources = [
|
||||
'assets/js/auth.js',
|
||||
'assets/js/author.js',
|
||||
'assets/js/routes/user-center.js',
|
||||
'assets/js/order-center.js',
|
||||
'assets/js/credits.js',
|
||||
'assets/js/signin.js',
|
||||
'assets/js/reward.js',
|
||||
'assets/js/report.js',
|
||||
'assets/js/page-navs.js',
|
||||
'assets/js/section-navs.js',
|
||||
'assets/js/posts-navs-page.js',
|
||||
'assets/js/front-submit.js',
|
||||
'assets/js/mini-upload.js',
|
||||
'assets/js/page-template.js',
|
||||
'assets/js/page-edit.js',
|
||||
'assets/js/precode.js',
|
||||
'assets/js/post-share.js',
|
||||
'assets/js/poster-share.js',
|
||||
'assets/js/pay-vip.js',
|
||||
'assets/js/video-player.js',
|
||||
'assets/js/download-status.js',
|
||||
'assets/js/ban-appeal-page.js',
|
||||
'assets/js/docs-navigation.js',
|
||||
'assets/js/input-expand.js',
|
||||
'assets/js/waterfall.js',
|
||||
'assets/js/yiyan.js',
|
||||
'assets/js/messages.js',
|
||||
'assets/js/site-notice.js',
|
||||
'assets/js/user-badge-actions.js',
|
||||
];
|
||||
|
||||
const readyPattern = /(?:document\.addEventListener\(\s*['"]DOMContentLoaded['"]|document\.readyState\s*===|jQuery\(document\)\.ready\s*\()/;
|
||||
|
||||
test('global DOM boot is the only initial page lifecycle owner', () => {
|
||||
const runtime = read('assets/js/aksrt-runtime.js');
|
||||
const registry = read('assets/js/rehydrate.js');
|
||||
assert.match(registry, /boot:\s*function/);
|
||||
assert.match(registry, /register:[\s\S]*?_booted/);
|
||||
assert.match(runtime, /AksrtFrontend\.boot\(root\)/);
|
||||
assert.match(runtime, /aksrt\.autoFun\(document, 'init'\)/);
|
||||
assert.match(runtime, /reason === 'init'[\s\S]*?AksrtFrontend\.boot\(root\)[\s\S]*?else[\s\S]*?AksrtFrontend\.rehydrate\(root, reason\)/);
|
||||
});
|
||||
|
||||
test('public bundle components register instead of owning DOM ready', () => {
|
||||
for (const file of publicSources) {
|
||||
const source = read(file);
|
||||
assert.doesNotMatch(source, readyPattern, `${file} still owns a DOM-ready boot`);
|
||||
assert.match(source, /AksrtFrontend\.register\(/, `${file} must register with the global lifecycle`);
|
||||
}
|
||||
});
|
||||
|
||||
test('active routed UI scripts register with the global lifecycle', () => {
|
||||
for (const file of routedSources) {
|
||||
const source = read(file);
|
||||
if (/API|coordinator|runtime/i.test(source.slice(0, 500)) && !/querySelector|addEventListener/.test(source)) continue;
|
||||
assert.doesNotMatch(source, readyPattern, `${file} still owns a DOM-ready boot`);
|
||||
assert.match(source, /AksrtFrontend\.register\(/, `${file} must register with the global lifecycle`);
|
||||
}
|
||||
});
|
||||
|
||||
test('high-risk routed components remain idempotent under global rehydrate', () => {
|
||||
const pageNavs = read('assets/js/page-navs.js');
|
||||
const sectionNavs = read('assets/js/section-navs.js');
|
||||
const poster = read('assets/js/poster-share.js');
|
||||
|
||||
assert.match(pageNavs, /__aksrtPageNavInitialized/);
|
||||
assert.match(pageNavs, /var grid = self\.root\.querySelector\('\.aksrt-doc-grid'\)/);
|
||||
assert.match(sectionNavs, /if \(scrollspyBound\) return/);
|
||||
assert.match(sectionNavs, /if \(autoHashHandled \|\| !window\.location\.hash\) return/);
|
||||
assert.match(poster, /triggers\.filter\(function \(el\) \{ return el\.dataset\.posterInit !== '1'; \}\)/);
|
||||
assert.doesNotMatch(poster, /triggers\.some\(function \(el\) \{ return el\.dataset\.posterInit === '1'; \}\)/);
|
||||
});
|
||||
|
||||
test('resource and SDK load listeners are not mistaken for page boot', () => {
|
||||
const captcha = read('assets/js/captcha-front.js');
|
||||
const color = read('assets/js/color-extract.js');
|
||||
assert.match(captcha, /\.onload\s*=|addEventListener\(['"]load['"]/);
|
||||
assert.match(color, /addEventListener\(['"]load['"]/);
|
||||
assert.doesNotMatch(captcha, /DOMContentLoaded/);
|
||||
assert.doesNotMatch(color, /DOMContentLoaded/);
|
||||
});
|
||||
|
||||
test('route scripts that use the registry load after the public runtime', () => {
|
||||
const scripts = read('src/Core/ScriptsPart1b.php') + read('src/Core/ScriptsPart1c.php');
|
||||
const files = ['section-navs.js', 'page-navs.js', 'posts-navs-page.js', 'author.js', 'auth.js'];
|
||||
for (const file of files) {
|
||||
const uri = scripts.indexOf("/assets/js/" + file);
|
||||
assert.notEqual(uri, -1, `${file} must be enqueued`);
|
||||
const blockStart = scripts.lastIndexOf('wp_enqueue_script(', uri);
|
||||
const blockEnd = scripts.indexOf(');', uri);
|
||||
const block = scripts.slice(blockStart, blockEnd + 2);
|
||||
assert.match(block, /aksrt-runtime/, `${file} must depend on aksrt-runtime`);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,85 @@
|
||||
'use strict';
|
||||
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const vm = require('node:vm');
|
||||
const test = require('node:test');
|
||||
|
||||
const root = path.resolve(__dirname, '..', '..');
|
||||
const read = (file) => fs.readFileSync(path.join(root, file), 'utf8');
|
||||
|
||||
test('homepage uses the global DOM lifecycle without a second ready path', () => {
|
||||
const runtime = read('assets/js/aksrt-runtime.js');
|
||||
const homepage = read('assets/js/homepage-fixed.js');
|
||||
|
||||
assert.match(runtime, /aksrt\.autoFun\s*=\s*function\s*\(root, reason\)/);
|
||||
assert.match(runtime, /function initRuntime\(\)\s*\{\s*aksrt\.autoFun\(document, 'init'\);/s);
|
||||
assert.doesNotMatch(runtime, /function initRuntime\(\)\s*\{\s*aksrt\.autoFun\(document\);/s);
|
||||
|
||||
assert.match(homepage, /window\.AksrtFrontend\.register\('aksrt-homepage', init\)/);
|
||||
assert.doesNotMatch(homepage, /DOMContentLoaded/);
|
||||
assert.doesNotMatch(homepage, /document\.querySelectorAll\('\[data-sort-dropdown-trigger\]'\)/);
|
||||
assert.doesNotMatch(homepage, /document\.querySelectorAll\('\.aksrt-homepage__stream'\)/);
|
||||
assert.doesNotMatch(homepage, /document\.querySelectorAll\('\.aksrt-homepage__tabs\.home-tab-nav-box'\)/);
|
||||
assert.match(homepage, /dataset\.aksrtHomeTabsBound === '1'/);
|
||||
assert.match(homepage, /dataset\.aksrtSortDropdownBound === '1'/);
|
||||
assert.match(homepage, /dataset\.aksrtSortbarBound === '1'/);
|
||||
assert.match(homepage, /dataset\.aksrtStickyTabsBound === '1'/);
|
||||
});
|
||||
|
||||
test('homepage initializer is registered once and remains idempotent across rehydrate calls', () => {
|
||||
const source = read('assets/js/homepage-fixed.js');
|
||||
const registrations = [];
|
||||
let sortbarClickBindings = 0;
|
||||
const sortbar = {
|
||||
dataset: {},
|
||||
getAttribute() {
|
||||
return null;
|
||||
},
|
||||
addEventListener(type) {
|
||||
if (type === 'click') sortbarClickBindings++;
|
||||
},
|
||||
};
|
||||
const stream = {
|
||||
querySelector(selector) {
|
||||
return selector === '.aksrt-homepage__sortbar' ? sortbar : null;
|
||||
},
|
||||
};
|
||||
const scope = {
|
||||
querySelectorAll(selector) {
|
||||
return selector === '.aksrt-homepage__stream' ? [stream] : [];
|
||||
},
|
||||
};
|
||||
const context = {
|
||||
window: {
|
||||
AksrtFrontend: {
|
||||
register(name, init) {
|
||||
registrations.push({ name, init });
|
||||
},
|
||||
},
|
||||
},
|
||||
document: scope,
|
||||
console,
|
||||
URLSearchParams,
|
||||
URL,
|
||||
setTimeout,
|
||||
clearTimeout,
|
||||
};
|
||||
context.window.window = context.window;
|
||||
context.window.document = scope;
|
||||
vm.runInNewContext(source, context, { filename: 'homepage-fixed.js' });
|
||||
|
||||
assert.equal(registrations.length, 1);
|
||||
assert.equal(registrations[0].name, 'aksrt-homepage');
|
||||
assert.equal(typeof registrations[0].init, 'function');
|
||||
registrations[0].init(scope, 'init');
|
||||
registrations[0].init(scope, 'ajax');
|
||||
assert.equal(sortbarClickBindings, 1);
|
||||
assert.equal(sortbar.dataset.aksrtSortbarBound, '1');
|
||||
});
|
||||
|
||||
test('homepage AJAX content continues to use the shared ajax rehydrate contract', () => {
|
||||
const homepage = read('assets/js/homepage-fixed.js');
|
||||
assert.match(homepage, /window\.AksrtFrontend\.rehydrate\(panel, 'ajax'\)/);
|
||||
});
|
||||
@@ -149,7 +149,9 @@ test('OAuth result handler maps safe errors and preserves unrelated URL state',
|
||||
activeElement: null,
|
||||
body: { classList: { add() {}, remove() {} } },
|
||||
}
|
||||
let authInit = null
|
||||
const window = {
|
||||
AksrtFrontend: { register: (_name, init) => { authInit = init } },
|
||||
aksrtData: {},
|
||||
URL,
|
||||
location,
|
||||
@@ -175,6 +177,7 @@ test('OAuth result handler maps safe errors and preserves unrelated URL state',
|
||||
Math,
|
||||
Promise,
|
||||
})
|
||||
authInit(document, 'init')
|
||||
assert.deepEqual(notices, [{ message: '第三方授权失败,请重试', type: 'danger' }])
|
||||
assert.equal(replaced, '/sign/?keep=1#section')
|
||||
assert.equal(replaced.includes('script'), false)
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
'use strict';
|
||||
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const test = require('node:test');
|
||||
|
||||
const root = path.resolve(__dirname, '..', '..');
|
||||
const read = (file) => fs.readFileSync(path.join(root, file), 'utf8');
|
||||
|
||||
test('public bundle has one source list and one generated legacy main artifact', () => {
|
||||
const build = read('tools/build-public-assets.mjs');
|
||||
assert.match(build, /'assets\/js\/rehydrate\.js'[\s\S]*?'assets\/js\/aksrt-runtime\.js'/);
|
||||
assert.match(build, /'assets\/js\/runtime\/main\.min\.js'/);
|
||||
assert.match(build, /async function buildRuntimeMainMin\(\)/);
|
||||
assert.match(build, /assets\/js\/runtime\/main\.js/);
|
||||
assert.match(build, /await buildRuntimeMainMin\(\)/);
|
||||
});
|
||||
|
||||
test('global lifecycle source precedes every registered public component', () => {
|
||||
const build = read('tools/build-public-assets.mjs');
|
||||
const registry = build.indexOf("'assets/js/rehydrate.js'");
|
||||
const runtime = build.indexOf("'assets/js/aksrt-runtime.js'");
|
||||
const legacy = build.indexOf("'assets/js/runtime/main.min.js'");
|
||||
assert.ok(registry >= 0 && registry < runtime && runtime < legacy);
|
||||
});
|
||||
|
||||
test('deleted orphan entry files do not return to enqueue or build graphs', () => {
|
||||
const graph = [
|
||||
read('tools/build-public-assets.mjs'),
|
||||
read('src/Core/ScriptsPart1b.php'),
|
||||
read('src/Core/ScriptsPart1c.php'),
|
||||
].join('\n');
|
||||
assert.equal(fs.existsSync(path.join(root, 'assets/js/main.js')), false);
|
||||
assert.equal(fs.existsSync(path.join(root, 'assets/js/loader.js')), false);
|
||||
assert.doesNotMatch(graph, /assets\/js\/(?:main|loader)\.js/);
|
||||
});
|
||||
|
||||
test('built public JavaScript contains the canonical global boot', () => {
|
||||
const bundle = read('assets/js/build/public.js');
|
||||
assert.match(bundle, /AksrtFrontend\.boot\(root\)/);
|
||||
assert.match(bundle, /aksrt\.autoFun\(document, 'init'\)/);
|
||||
assert.match(bundle, /aksrt:ready/);
|
||||
});
|
||||
@@ -0,0 +1,97 @@
|
||||
'use strict';
|
||||
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const vm = require('node:vm');
|
||||
const test = require('node:test');
|
||||
|
||||
const root = path.resolve(__dirname, '..', '..');
|
||||
const source = fs.readFileSync(path.join(root, 'assets/js/rehydrate.js'), 'utf8');
|
||||
|
||||
function createRuntime() {
|
||||
const events = [];
|
||||
const document = {
|
||||
dispatchEvent(event) {
|
||||
events.push(event);
|
||||
return true;
|
||||
},
|
||||
};
|
||||
function CustomEvent(type, options) {
|
||||
this.type = type;
|
||||
this.bubbles = Boolean(options && options.bubbles);
|
||||
this.detail = options && options.detail;
|
||||
}
|
||||
const errors = [];
|
||||
const context = {
|
||||
window: {},
|
||||
document,
|
||||
CustomEvent,
|
||||
console: {
|
||||
error(...args) {
|
||||
errors.push(args);
|
||||
},
|
||||
},
|
||||
};
|
||||
context.window.window = context.window;
|
||||
context.window.document = document;
|
||||
vm.runInNewContext(source, context, { filename: 'rehydrate.js' });
|
||||
return { api: context.window.AksrtFrontend, document, events, errors };
|
||||
}
|
||||
|
||||
test('global DOM boot runs registered components once with init reason', () => {
|
||||
const runtime = createRuntime();
|
||||
const calls = [];
|
||||
runtime.api.register('first', (rootNode, reason) => calls.push([rootNode, reason]));
|
||||
|
||||
runtime.api.boot(runtime.document);
|
||||
runtime.api.boot(runtime.document);
|
||||
|
||||
assert.equal(runtime.api.isBooted(), true);
|
||||
assert.deepEqual(calls, [[runtime.document, 'init']]);
|
||||
assert.deepEqual(runtime.events.map((event) => event.type), ['aksrt:rehydrated', 'aksrt:ready']);
|
||||
assert.equal(runtime.events[0].detail.reason, 'init');
|
||||
assert.equal(runtime.events[1].detail.reason, 'init');
|
||||
});
|
||||
|
||||
test('late registrations initialize immediately after global boot', () => {
|
||||
const runtime = createRuntime();
|
||||
const calls = [];
|
||||
runtime.api.boot(runtime.document);
|
||||
runtime.api.register('late', (rootNode, reason) => calls.push([rootNode, reason]));
|
||||
|
||||
assert.deepEqual(calls, [[runtime.document, 'init']]);
|
||||
assert.deepEqual(Array.from(runtime.api.getRegistered()), ['late']);
|
||||
});
|
||||
|
||||
test('same-name registration replaces the owner without duplicating it', () => {
|
||||
const runtime = createRuntime();
|
||||
const calls = [];
|
||||
runtime.api.register('owner', () => calls.push('old'));
|
||||
runtime.api.register('owner', () => calls.push('new'));
|
||||
runtime.api.boot(runtime.document);
|
||||
|
||||
assert.deepEqual(Array.from(runtime.api.getRegistered()), ['owner']);
|
||||
assert.deepEqual(calls, ['new']);
|
||||
});
|
||||
|
||||
test('rehydrate preserves root and reason while isolating component failures', () => {
|
||||
const runtime = createRuntime();
|
||||
const fragment = {
|
||||
dispatchEvent(event) {
|
||||
runtime.events.push(event);
|
||||
return true;
|
||||
},
|
||||
};
|
||||
const calls = [];
|
||||
runtime.api.register('broken', () => { throw new Error('broken'); });
|
||||
runtime.api.register('healthy', (rootNode, reason) => calls.push([rootNode, reason]));
|
||||
|
||||
runtime.api.rehydrate(fragment, 'modal');
|
||||
|
||||
assert.deepEqual(calls, [[fragment, 'modal']]);
|
||||
assert.equal(runtime.errors.length, 1);
|
||||
assert.equal(runtime.events.at(-1).type, 'aksrt:rehydrated');
|
||||
assert.equal(runtime.events.at(-1).detail.reason, 'modal');
|
||||
assert.equal(runtime.events.at(-1).bubbles, true);
|
||||
});
|
||||
@@ -240,7 +240,8 @@ test('balance center actions use direct fixed-id notyf flows', () => {
|
||||
assert.match(signinController, /querySelectorAll\('\[data-signin-btn\]'\)/);
|
||||
assert.match(signinController, /freshButtons\.forEach[\s\S]*?addEventListener\('click'/);
|
||||
assert.match(credits, /onTimeout:[\s\S]*?notyf\([^;]+?'danger'[^;]+?'aksrt-balance-charge-payment-toast'\)/);
|
||||
assert.match(credits, /register\('credits',[\s\S]*?initSigninGoto\(\);[\s\S]*?initBalanceCharge\(\);[\s\S]*?initTransfer\(\);[\s\S]*?initPointsExchange\(\);[\s\S]*?initWithdraw\(\);/);
|
||||
assert.match(credits, /function bootAssets\(root, reason\)[\s\S]*?initSigninGoto\(root\);[\s\S]*?initBalanceCharge\(root\);[\s\S]*?initTransfer\(root\);[\s\S]*?initPointsExchange\(root\);[\s\S]*?initWithdraw\(root\);/);
|
||||
assert.match(credits, /register\('credits', bootAssets\)/);
|
||||
assert.doesNotMatch(credits, /function initSignin\(|\/signin\/today|POST \/signin/);
|
||||
assert.match(signinController, /aksrtSigninInitialized/);
|
||||
assert.match(credits, /aksrtPointsExchangeInitialized[\s\S]*?aksrtWithdrawInitialized/);
|
||||
@@ -321,7 +322,7 @@ test('profile save uses AJAX rehydrate and a fixed-id notyf flow without query f
|
||||
const scripts = read('src/Core/ScriptsPart1b.php');
|
||||
|
||||
assert.match(profile, /function initProfileForm\(root\)[\s\S]*?aksrtProfileInitialized[\s\S]*?addEventListener\('submit'/);
|
||||
assert.match(profile, /register\('aksrt-profile-form',[\s\S]*?initProfileForm\(root\)/);
|
||||
assert.match(profile, /register\('aksrt-user-center',[\s\S]*?initProfileForm\(root\)/);
|
||||
assert.match(profile, /notyf\([^;]+?'load'[^;]+?'aksrt-profile-save-toast'\);/);
|
||||
assert.match(profile, /notyf\([^;]+?'success'[^;]+?'aksrt-profile-save-toast'\);/);
|
||||
assert.match(profile, /notyf\([^;]+?'danger'[^;]+?'aksrt-profile-save-toast'\);/);
|
||||
@@ -350,7 +351,7 @@ test('settings actions use rehydrated fixed-id notyf flows', () => {
|
||||
assert.match(userCenter, /notyf\([^;]+?'load'[^;]+?toastId\);/);
|
||||
assert.match(userCenter, /notyf\([^;]+?'success'[^;]+?toastId\);/);
|
||||
assert.match(userCenter, /notyf\([^;]+?'danger'[^;]+?toastId\);/);
|
||||
assert.match(userCenter, /register\('aksrt-settings',[\s\S]*?initSettings\(root\);[\s\S]*?initBindPhone\(root\);/);
|
||||
assert.match(userCenter, /register\('aksrt-user-center',[\s\S]*?initSettings\(root\);[\s\S]*?initBindPhone\(root\);/);
|
||||
assert.match(userCenter, /aksrtSettingsInitialized/);
|
||||
assert.match(userCenter, /oauth_action[\s\S]*?notyf\(message, type\)[\s\S]*?history\.replaceState/);
|
||||
assert.doesNotMatch(userCenter, /oauth_unbound/);
|
||||
|
||||
@@ -173,6 +173,22 @@ async function buildScriptBundle() {
|
||||
await writeFile(path.join(jsBuildDir, 'public.js'), `${sections.join('\n\n')}\n`, 'utf8');
|
||||
}
|
||||
|
||||
async function buildRuntimeMainMin() {
|
||||
const sourcePath = path.join(repoRoot, 'assets/js/runtime/main.js');
|
||||
const outputPath = path.join(repoRoot, 'assets/js/runtime/main.min.js');
|
||||
const source = await readFile(sourcePath, 'utf8');
|
||||
const minified = await transform(source, {
|
||||
charset: 'utf8',
|
||||
legalComments: 'inline',
|
||||
loader: 'js',
|
||||
minifyIdentifiers: false,
|
||||
minifySyntax: true,
|
||||
minifyWhitespace: true,
|
||||
sourcefile: 'runtime/main.js',
|
||||
});
|
||||
await writeFile(outputPath, minified.code, 'utf8');
|
||||
}
|
||||
|
||||
// 评论区硬切换后 main.min.css 由 main.css 重新生成,保持两者同步。
|
||||
async function buildMainMin() {
|
||||
const sourcePath = path.join(repoRoot, 'assets/css/main.css');
|
||||
@@ -190,6 +206,7 @@ async function buildMainMin() {
|
||||
|
||||
await mkdir(cssBuildDir, { recursive: true });
|
||||
await mkdir(jsBuildDir, { recursive: true });
|
||||
await buildRuntimeMainMin();
|
||||
// 先刷新 main.min.css,public.css 打包时才能读到最新内容。
|
||||
await buildMainMin();
|
||||
for (const [outputName, sources] of Object.entries(cssBundles)) {
|
||||
|
||||
Reference in New Issue
Block a user