- assets/vendor 全量迁移: fontawesome5→assets/fontawesome5, css→assets/css, js→assets/js/runtime(避开 14 个同名自有文件), img 合并去重→assets/img, fonts→assets/fonts; 删除 assets/vendor - libs 五个与 widgets/third-party 字节相同的库不重复入库, loader paths 改指向 - 运行时切换: _win.uri=assets 根, loader baseUrl=/js/runtime, enlighter 注入 路径同步; PHP 7 个引用文件切换并改名 $zibll_*→$runtime_* - 去品牌: Qinver 头注释/品牌 console.log/演示链接清除, 默认文案中性化 - 功能标识符改名: zib__→aksrt__, zib_ajax→aksrt_ajax, window.zib→ window.aksrtLegacy, zibllblock/*→aksrtblock/*, .zib-widget→.aksrt-panel, .zib-slider→.aksrt-slider, zib_menu_options meta 键等 - 自有 CSS 改名: legacy-utilities/compat-vars/footer shell - admin SPA 重建; 契约测试同步(路径/断言/文件更名) - 例外保留: tests/visual 对照环境与 fixtures 前缀(外部 Zibll 产品引用) 验证: php -l 133 个改动文件通过; runtime 86 个 JS node --check 通过; 契约测试 68/70(2 个失败经 stash 对照确认为存量问题)
706 lines
25 KiB
JavaScript
706 lines
25 KiB
JavaScript
/**
|
||
* AKSRT Comment System — AJAX submit, captcha, ordering, author filter
|
||
*/
|
||
(function () {
|
||
"use strict";
|
||
|
||
function initCommentSystem() {
|
||
var form = document.querySelector("#commentform");
|
||
if (!form) return;
|
||
|
||
// 修复:同时匹配 button 和 input 元素
|
||
var submitBtn = form.querySelector('[type="submit"]');
|
||
if (!submitBtn) return;
|
||
var isInputSubmit = submitBtn.tagName === 'INPUT';
|
||
|
||
// 保存原始按钮内容(用于恢复)
|
||
var originalBtnHTML = isInputSubmit ? submitBtn.value : submitBtn.innerHTML;
|
||
|
||
function setSubmitBtnContent(html, textFallback) {
|
||
if (isInputSubmit) {
|
||
submitBtn.value = textFallback;
|
||
} else {
|
||
submitBtn.innerHTML = html;
|
||
}
|
||
}
|
||
|
||
// 状态管理
|
||
var isSubmitting = false;
|
||
var countdownTimer = null;
|
||
|
||
// 显示/隐藏加载状态
|
||
function setLoading(loading) {
|
||
if (loading) {
|
||
isSubmitting = true;
|
||
submitBtn.classList.add("is-loading");
|
||
submitBtn.disabled = true;
|
||
var loadingText = (window.aksrtData && aksrtData.commentSubmittingText) || '发送中...';
|
||
setSubmitBtnContent('<i class="fa fas fa-spinner fa-spin"></i> ' + loadingText, loadingText);
|
||
} else {
|
||
isSubmitting = false;
|
||
submitBtn.classList.remove("is-loading");
|
||
submitBtn.classList.remove('countdown-active');
|
||
submitBtn.disabled = false;
|
||
setSubmitBtnContent(originalBtnHTML, originalBtnHTML);
|
||
}
|
||
}
|
||
|
||
// 收集表单数据(包含验证码字段)
|
||
function collectFormData() {
|
||
var formData = new FormData(form);
|
||
|
||
// 确保包含必要的隐藏字段
|
||
var postId = document.querySelector('input[name="comment_post_ID"]');
|
||
if (postId && !formData.get('comment_post_ID')) {
|
||
formData.append('comment_post_ID', postId.value);
|
||
}
|
||
|
||
return formData;
|
||
}
|
||
|
||
// 从 wp_die() HTML 中提取错误信息
|
||
function extractErrorMessage(html) {
|
||
// WordPress wp_die() 输出格式: <p>错误信息</p>
|
||
var match = html.match(/<p[^>]*>([^<]+)<\/p>/i);
|
||
return match ? match[1].trim() : '未知错误';
|
||
}
|
||
|
||
// 从错误消息中提取等待时间(秒)
|
||
function extractWaitTime(msg) {
|
||
var match = msg.match(/(\d+)\s*秒/);
|
||
return match ? parseInt(match[1]) : 0;
|
||
}
|
||
|
||
// 启动倒计时(用于频率限制)
|
||
function startCountdown(seconds) {
|
||
if (countdownTimer) clearInterval(countdownTimer);
|
||
|
||
submitBtn.classList.add('countdown-active');
|
||
submitBtn.disabled = true;
|
||
var remaining = seconds;
|
||
|
||
countdownTimer = setInterval(function () {
|
||
setSubmitBtnContent(
|
||
'<i class="fa fas fa-clock"></i> 请等待 ' + remaining + 's',
|
||
'请等待 ' + remaining + 's'
|
||
);
|
||
|
||
if (--remaining <= 0) {
|
||
clearInterval(countdownTimer);
|
||
countdownTimer = null;
|
||
submitBtn.classList.remove('countdown-active', 'is-loading');
|
||
submitBtn.disabled = false;
|
||
setSubmitBtnContent(originalBtnHTML, originalBtnHTML);
|
||
isSubmitting = false;
|
||
}
|
||
}, 1000);
|
||
}
|
||
|
||
function updateCommentCount(delta) {
|
||
var countEl = document.querySelector('#comments .title-theme small');
|
||
if (!countEl) return;
|
||
var text = countEl.textContent || '';
|
||
var match = text.match(/(\d+)/);
|
||
if (!match) return;
|
||
var nextCount = Math.max(0, parseInt(match[1], 10) + delta);
|
||
countEl.textContent = text.replace(match[1], String(nextCount));
|
||
}
|
||
function handleResponse(responseText, statusCode) {
|
||
try {
|
||
// 情况1: 成功提交 - 包含评论ID或成功标记
|
||
if (statusCode === 200 || statusCode === 201) {
|
||
if (responseText.includes('comment-submitted') ||
|
||
responseText.indexOf('id="comment-') !== -1 ||
|
||
responseText.indexOf('awaiting-moderation') !== -1) {
|
||
|
||
// 区分是否需要审核
|
||
if (responseText.indexOf('审核') !== -1 ||
|
||
responseText.indexOf('moderation') !== -1 ||
|
||
responseText.includes('awaiting-moderation')) {
|
||
notyf('评论已提交,等待管理员审核', 'info');
|
||
} else {
|
||
notyf('评论发布成功', 'success');
|
||
}
|
||
|
||
// 清空文本框
|
||
var textarea = form.querySelector('#comment');
|
||
if (textarea) textarea.value = '';
|
||
|
||
// 重置回复状态
|
||
var replyInfo = document.getElementById('comment-reply-info');
|
||
if (replyInfo) replyInfo.style.display = 'none';
|
||
|
||
// 刷新评论列表(延迟执行,确保后端处理完成)
|
||
setTimeout(function () {
|
||
reloadCommentList();
|
||
}, 500);
|
||
setLoading(false);
|
||
|
||
return true;
|
||
}
|
||
}
|
||
|
||
// 情况2: HTTP 429 频率限制
|
||
if (statusCode === 429) {
|
||
var errorMsg = extractErrorMessage(responseText);
|
||
var waitSeconds = extractWaitTime(errorMsg);
|
||
|
||
notyf(errorMsg, 'warning');
|
||
|
||
if (waitSeconds > 0) {
|
||
startCountdown(waitSeconds);
|
||
} else {
|
||
setLoading(false); // 无具体等待时间时恢复按钮
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
// 情况3: HTTP 403 权限不足(地区/IP/关键词等)
|
||
if (statusCode === 403) {
|
||
var forbiddenMsg = extractErrorMessage(responseText);
|
||
notyf(forbiddenMsg, 'danger');
|
||
setLoading(false);
|
||
return false;
|
||
}
|
||
|
||
// 情况4: 包含WordPress错误信息
|
||
var errorMatch = responseText.match(/<p[^>]*>([^<]*(?:错误|失败|error|Error)[^<]*)<\/p>/i);
|
||
if (errorMatch) {
|
||
notyf(errorMatch[1].trim(), 'danger');
|
||
setLoading(false);
|
||
return false;
|
||
}
|
||
// 默认情况:可能是成功或其他
|
||
notyf('评论已提交', 'success');
|
||
var textarea2 = form.querySelector('#comment');
|
||
if (textarea2) textarea2.value = '';
|
||
|
||
// 局部刷新评论列表(不再整页 reload)
|
||
setTimeout(function () {
|
||
reloadCommentList();
|
||
}, 500);
|
||
setLoading(false);
|
||
|
||
return true;
|
||
|
||
} catch (e) {
|
||
console.error('[AKSRT Comment] 解析响应失败:', e);
|
||
notyf('响应解析异常,请重试', 'danger');
|
||
setLoading(false);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// 执行实际的 AJAX 请求 — local insert instead of full-page re-fetch
|
||
function performSubmit() {
|
||
setLoading(true);
|
||
|
||
var formData = collectFormData();
|
||
var restRoot = (window.aksrtData && aksrtData.siteUrl) ? String(aksrtData.siteUrl).replace(/\/$/, '') : '';
|
||
var editId = form.querySelector('[name="edit_comment_ID"]');
|
||
var isEdit = editId && parseInt(editId.value, 10) > 0;
|
||
var restBase = (restRoot || '') + '/wp-json/aksrt/v1/comment/' + (isEdit ? 'edit' : 'submit');
|
||
|
||
// Try REST endpoint for local-insert HTML response
|
||
var restBody = {};
|
||
formData.forEach(function (v, k) { restBody[k] = v; });
|
||
if (isEdit) {
|
||
restBody.comment_id = parseInt(editId.value, 10);
|
||
restBody.content = restBody.comment || restBody.content || '';
|
||
}
|
||
|
||
fetch(restBase, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'X-WP-Nonce': (window.aksrtData && aksrtData.restNonce) || ''
|
||
},
|
||
credentials: 'same-origin',
|
||
body: JSON.stringify(restBody)
|
||
})
|
||
.then(function (r) { return r.json(); })
|
||
.then(function (json) {
|
||
if (isEdit && json && json.success) {
|
||
var cid = restBody.comment_id;
|
||
var contentEl = document.querySelector('#comment-content-' + cid + ', [data-comment-id="' + cid + '"] .comment-content');
|
||
var rendered = (json.data && json.data.content) || json.content || '';
|
||
if (contentEl && rendered) contentEl.innerHTML = rendered;
|
||
var textarea = form.querySelector('#comment');
|
||
if (textarea) textarea.value = '';
|
||
if (editId) editId.remove();
|
||
restoreRespondPosition();
|
||
setLoading(false);
|
||
notyf(json.message || '评论已更新', 'success');
|
||
var respondEl = document.getElementById('respond');
|
||
if (respondEl && window.AksrtFixedInput) window.AksrtFixedInput(respondEl, 'hide');
|
||
return;
|
||
}
|
||
if (json && json.success && json.html) {
|
||
// Local insert: prepend new comment HTML
|
||
localInsertComment(json.html, json.is_reply, json.parent_id, json.needs_moderation);
|
||
|
||
var textarea = form.querySelector('#comment');
|
||
if (textarea) textarea.value = '';
|
||
|
||
var replyInfo = document.getElementById('comment-reply-info');
|
||
if (replyInfo) replyInfo.style.display = 'none';
|
||
// Reset captcha after successful submit
|
||
try {
|
||
var captchaScene = window.AKSRTCaptchaState &&
|
||
window.AKSRTCaptchaState.scenes &&
|
||
window.AKSRTCaptchaState.scenes.comment;
|
||
if (captchaScene && typeof captchaScene.reset === 'function') {
|
||
captchaScene.reset();
|
||
}
|
||
} catch (e) { /* ignore */ }
|
||
|
||
// Wait time countdown
|
||
if (json.wait_time && json.wait_time > 0) {
|
||
startCountdown(json.wait_time);
|
||
} else {
|
||
setLoading(false);
|
||
}
|
||
|
||
// Move respond back to original position
|
||
restoreRespondPosition();
|
||
|
||
// Hide mobile FixedInput after successful submit.
|
||
var respondEl = document.getElementById('respond');
|
||
if (respondEl && window.AksrtFixedInput) {
|
||
window.AksrtFixedInput(respondEl, 'hide');
|
||
} else if (respondEl) {
|
||
respondEl.classList.remove('show');
|
||
}
|
||
|
||
// If editing via moveForm, clear edit field.
|
||
var editField = form.querySelector('[name="edit_comment_ID"]');
|
||
if (editField) editField.remove();
|
||
|
||
return;
|
||
}
|
||
|
||
if (json && json.code) {
|
||
notyf(json.message || '评论提交失败', 'danger');
|
||
try {
|
||
var failScene = window.AKSRTCaptchaState &&
|
||
window.AKSRTCaptchaState.scenes &&
|
||
window.AKSRTCaptchaState.scenes.comment;
|
||
if (failScene && typeof failScene.reset === 'function') {
|
||
failScene.reset();
|
||
}
|
||
} catch (e) { /* ignore */ }
|
||
if (json.wait_time) startCountdown(json.wait_time);
|
||
else setLoading(false);
|
||
return;
|
||
}
|
||
|
||
notyf('评论已提交', 'success');
|
||
setLoading(false);
|
||
setTimeout(function () { reloadCommentList(); }, 500);
|
||
})
|
||
.catch(function () {
|
||
// Fallback: submit to wp-comments-post.php directly
|
||
performLegacySubmit();
|
||
});
|
||
}
|
||
|
||
function localInsertComment(html, isReply, parentId, needsModeration) {
|
||
var temp = document.createElement('div');
|
||
temp.innerHTML = html;
|
||
var newComment = temp.firstElementChild;
|
||
if (!newComment) { reloadCommentList(); return; }
|
||
|
||
newComment.style.overflow = 'hidden';
|
||
newComment.style.maxHeight = '0';
|
||
newComment.style.opacity = '0';
|
||
newComment.style.transition = 'max-height 0.4s ease, opacity 0.3s ease';
|
||
if (isReply && parentId) {
|
||
var parentComment = document.querySelector('#comment-' + parentId);
|
||
if (parentComment) {
|
||
var children = parentComment.querySelector(':scope > .children');
|
||
if (!children) {
|
||
children = document.createElement('ol');
|
||
children.className = 'children';
|
||
parentComment.appendChild(children);
|
||
}
|
||
children.insertBefore(newComment, children.firstChild);
|
||
} else {
|
||
prependToCommentList(newComment);
|
||
}
|
||
} else {
|
||
prependToCommentList(newComment);
|
||
}
|
||
|
||
// slideDown animation
|
||
requestAnimationFrame(function () {
|
||
newComment.style.maxHeight = newComment.scrollHeight + 100 + 'px';
|
||
newComment.style.opacity = '1';
|
||
setTimeout(function () {
|
||
newComment.style.maxHeight = '';
|
||
newComment.style.overflow = '';
|
||
newComment.style.transition = '';
|
||
}, 500);
|
||
});
|
||
|
||
if (needsModeration) {
|
||
notyf('评论已提交,等待管理员审核', 'info');
|
||
} else {
|
||
notyf('评论发布成功', 'success');
|
||
}
|
||
|
||
if (window.AksrtFrontend) AksrtFrontend.rehydrate(newComment, 'ajax');
|
||
updateCommentCount(1);
|
||
}
|
||
|
||
function prependToCommentList(el) {
|
||
var list = document.querySelector('#comments .commentlist');
|
||
if (!list) return;
|
||
// 插到筛选栏之后、最新评论之前
|
||
var filter = list.querySelector('.comment-filter');
|
||
if (filter && filter.nextSibling) {
|
||
list.insertBefore(el, filter.nextSibling);
|
||
} else {
|
||
list.insertBefore(el, list.firstChild);
|
||
}
|
||
}
|
||
|
||
function restoreRespondPosition() {
|
||
var respond = document.getElementById('respond');
|
||
var placeholder = document.getElementById('wp-temp-form-div');
|
||
if (respond && placeholder && placeholder.parentNode) {
|
||
placeholder.parentNode.insertBefore(respond, placeholder);
|
||
placeholder.remove();
|
||
}
|
||
}
|
||
// Legacy fallback: POST to wp-comments-post.php
|
||
function performLegacySubmit() {
|
||
var formData = collectFormData();
|
||
var actionUrl = form.getAttribute('action') || '/wp-comments-post.php';
|
||
|
||
fetch(actionUrl, {
|
||
method: 'POST',
|
||
body: formData,
|
||
credentials: 'same-origin',
|
||
headers: { 'X-Requested-With': 'XMLHttpRequest' }
|
||
})
|
||
.then(function (response) {
|
||
return response.text().then(function (text) {
|
||
return { status: response.status, text: text, ok: response.ok };
|
||
});
|
||
})
|
||
.then(function (result) {
|
||
handleResponse(result.text, result.status);
|
||
})
|
||
.catch(function (error) {
|
||
console.error('[AKSRT Comment] 提交失败:', error);
|
||
|
||
if (error.message === 'Failed to fetch' || error.name === 'TypeError') {
|
||
notyf('网络连接失败,请检查网络后重试', 'danger');
|
||
} else {
|
||
notyf(error.message || '评论提交失败,请重试', 'danger');
|
||
}
|
||
|
||
setLoading(false);
|
||
})
|
||
.finally(function () {
|
||
// 兜底:避免异常分支漏掉状态恢复导致按钮卡在"发送中"
|
||
if (!countdownTimer && isSubmitting) {
|
||
setLoading(false);
|
||
}
|
||
});
|
||
}
|
||
|
||
// 核心表单提交事件处理器
|
||
function handleSubmit(e) {
|
||
// 如果已经在提交中或倒计时中,防止重复提交
|
||
if (isSubmitting || countdownTimer) {
|
||
e.preventDefault();
|
||
e.stopImmediatePropagation();
|
||
return false;
|
||
}
|
||
|
||
// 阻止默认表单提交
|
||
e.preventDefault();
|
||
e.stopImmediatePropagation();
|
||
// 检查验证码状态(如果有验证码组件)
|
||
var captchaScene = window.AKSRTCaptchaState &&
|
||
window.AKSRTCaptchaState.scenes &&
|
||
window.AKSRTCaptchaState.scenes.comment;
|
||
|
||
if (captchaScene && typeof captchaScene.verify === 'function') {
|
||
// 有验证码:先触发验证流程
|
||
setLoading(true);
|
||
|
||
captchaScene.verify(function (verified) {
|
||
if (verified !== false) {
|
||
// 验证通过,执行 AJAX 提交
|
||
performSubmit();
|
||
} else {
|
||
// 验证失败
|
||
notyf('人机验证未通过,请重试', 'warning');
|
||
setLoading(false);
|
||
}
|
||
});
|
||
} else {
|
||
// 无验证码或已经验证过:直接提交
|
||
performSubmit();
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
// 绑定表单提交事件(使用捕获阶段,高优先级)
|
||
form.addEventListener('submit', handleSubmit, true);
|
||
}
|
||
|
||
|
||
function getCommentsRestBase() {
|
||
var root = (window.aksrtData && aksrtData.siteUrl) ? String(aksrtData.siteUrl).replace(/\/$/, "") : "";
|
||
return root + "/wp-json/aksrt/v1";
|
||
}
|
||
|
||
function getCurrentCommentPostId() {
|
||
var input = document.querySelector('input[name="comment_post_ID"]');
|
||
if (input && input.value) return parseInt(input.value, 10) || 0;
|
||
var comments = document.getElementById("comments");
|
||
if (comments && comments.dataset.postId) return parseInt(comments.dataset.postId, 10) || 0;
|
||
return 0;
|
||
}
|
||
|
||
function getCurrentCommentOrder() {
|
||
var active = document.querySelector("#comments .comment-order-box li.active .comment-orderby");
|
||
if (active && active.dataset && active.dataset.order) return active.dataset.order;
|
||
var url = new URL(window.location.href);
|
||
return url.searchParams.get("aksrt_comment_order") || "newest";
|
||
}
|
||
|
||
function getCurrentAuthorOnly() {
|
||
var url = new URL(window.location.href);
|
||
if (url.searchParams.get("aksrt_author_only") === "1") return true;
|
||
var btn = document.querySelector("#comments .btn-only-author");
|
||
return !!(btn && btn.classList.contains("active") && btn.dataset.authorOnly === "0");
|
||
}
|
||
|
||
function applyFragmentPayload(commentsArea, data, urlState) {
|
||
if (!commentsArea || !data || !data.html) return;
|
||
|
||
// data.html 是完整的 <div id="postcomments">(含筛选、列表、分页)
|
||
var tempList = document.createElement("div");
|
||
tempList.innerHTML = data.html;
|
||
var newListWrap = tempList.querySelector("#postcomments");
|
||
if (!newListWrap) return;
|
||
|
||
var currentListWrap = commentsArea.querySelector("#postcomments");
|
||
if (currentListWrap) {
|
||
currentListWrap.replaceWith(newListWrap);
|
||
} else {
|
||
commentsArea.appendChild(newListWrap);
|
||
}
|
||
|
||
var currentCount = commentsArea.querySelector(".title-theme small");
|
||
if (currentCount && data.count_text) currentCount.textContent = data.count_text;
|
||
|
||
if (urlState && window.history && typeof window.history.replaceState === "function") {
|
||
window.history.replaceState(null, "", urlState);
|
||
}
|
||
if (window.AksrtFrontend) AksrtFrontend.rehydrate(commentsArea, "ajax");
|
||
}
|
||
|
||
function fetchCommentFragment(opts) {
|
||
opts = opts || {};
|
||
var postId = opts.postId || getCurrentCommentPostId();
|
||
if (!postId) return Promise.reject(new Error("missing post id"));
|
||
var order = opts.order || getCurrentCommentOrder() || "newest";
|
||
var authorOnly = !!opts.authorOnly;
|
||
var page = opts.page || 1;
|
||
var qs = new URLSearchParams();
|
||
qs.set("post_id", String(postId));
|
||
qs.set("order", order);
|
||
qs.set("page", String(page));
|
||
if (authorOnly) qs.set("author_only", "1");
|
||
var url = getCommentsRestBase() + "/comment/list?" + qs.toString();
|
||
return fetch(url, {
|
||
method: "GET",
|
||
credentials: "same-origin",
|
||
headers: {
|
||
"X-WP-Nonce": (window.aksrtData && aksrtData.restNonce) || ""
|
||
}
|
||
}).then(function (r) { return r.json(); });
|
||
}
|
||
|
||
/* ====== 评论列表动态刷新 ====== */
|
||
function showListLoading(commentsArea) {
|
||
var list = commentsArea.querySelector(".commentlist");
|
||
if (!list) return;
|
||
// 保留筛选栏,清空条目并显示 legacy 骨架
|
||
var filter = list.querySelector(".comment-filter");
|
||
var loader = list.querySelector(".post_ajax_loader");
|
||
var skeleton = loader ? loader.cloneNode(true) : null;
|
||
Array.prototype.slice.call(list.children).forEach(function (child) {
|
||
if (child !== filter && child !== loader) child.remove();
|
||
});
|
||
if (skeleton) {
|
||
skeleton.style.display = "block";
|
||
skeleton.removeAttribute("hidden");
|
||
list.appendChild(skeleton);
|
||
}
|
||
}
|
||
|
||
function reloadCommentList() {
|
||
var commentsArea = document.getElementById('comments');
|
||
if (!commentsArea) {
|
||
window.location.reload();
|
||
return;
|
||
}
|
||
showListLoading(commentsArea);
|
||
|
||
fetchCommentFragment({
|
||
order: getCurrentCommentOrder(),
|
||
authorOnly: getCurrentAuthorOnly(),
|
||
page: 1
|
||
}).then(function (json) {
|
||
if (json && json.success && json.data) {
|
||
applyFragmentPayload(commentsArea, json.data, null);
|
||
return;
|
||
}
|
||
throw new Error('fragment failed');
|
||
}).catch(function (error) {
|
||
console.error('[AKSRT Comment] 刷新评论列表失败:', error);
|
||
window.location.reload();
|
||
});
|
||
}
|
||
|
||
/* ====== 评论排序(最新 / 最早) ====== */
|
||
/**
|
||
* Locate #id within a rehydrate root.
|
||
* Document has getElementById; Element roots (AJAX panels) only have querySelector.
|
||
*/
|
||
function findInScope(scope, id) {
|
||
scope = scope || document;
|
||
if (!scope) return null;
|
||
if (scope.nodeType === 9) {
|
||
return scope.getElementById(id);
|
||
}
|
||
if (scope.nodeType === 1) {
|
||
if (scope.id === id) return scope;
|
||
return typeof scope.querySelector === "function"
|
||
? scope.querySelector("#" + id)
|
||
: null;
|
||
}
|
||
return null;
|
||
}
|
||
|
||
function initCommentOrder(root) {
|
||
var scope = root || document;
|
||
var commentsArea = findInScope(scope, "comments");
|
||
if (!commentsArea) return;
|
||
// Event delegation survives filter HTML replacement after AJAX rehydrate.
|
||
if (commentsArea.dataset.orderInit === "1") return;
|
||
commentsArea.dataset.orderInit = "1";
|
||
|
||
function renderLoadingState() {
|
||
showListLoading(commentsArea);
|
||
}
|
||
function applyCommentOrder(order) {
|
||
if (order !== "newest" && order !== "oldest" && order !== "hottest") {
|
||
order = "newest";
|
||
}
|
||
renderLoadingState();
|
||
var authorOnly = getCurrentAuthorOnly();
|
||
var url = new URL(window.location.href);
|
||
url.searchParams.set("aksrt_comment_order", order);
|
||
url.searchParams.delete("cpage");
|
||
if (authorOnly) url.searchParams.set("aksrt_author_only", "1");
|
||
else url.searchParams.delete("aksrt_author_only");
|
||
|
||
fetchCommentFragment({ order: order, authorOnly: authorOnly, page: 1 })
|
||
.then(function (json) {
|
||
if (json && json.success && json.data) {
|
||
applyFragmentPayload(commentsArea, json.data, url.toString());
|
||
return;
|
||
}
|
||
throw new Error("order fragment failed");
|
||
})
|
||
.catch(function (error) {
|
||
console.error("[AKSRT Comment] 排序刷新失败:", error);
|
||
window.location.href = url.toString();
|
||
});
|
||
}
|
||
|
||
function applyAuthorFilter(authorOnlyFlag) {
|
||
renderLoadingState();
|
||
var authorOnly = authorOnlyFlag === "1" || authorOnlyFlag === 1 || authorOnlyFlag === true;
|
||
var order = getCurrentCommentOrder();
|
||
var url = new URL(window.location.href);
|
||
if (authorOnly) url.searchParams.set("aksrt_author_only", "1");
|
||
else url.searchParams.delete("aksrt_author_only");
|
||
url.searchParams.delete("cpage");
|
||
if (order) url.searchParams.set("aksrt_comment_order", order);
|
||
|
||
fetchCommentFragment({ order: order, authorOnly: authorOnly, page: 1 })
|
||
.then(function (json) {
|
||
if (json && json.success && json.data) {
|
||
applyFragmentPayload(commentsArea, json.data, url.toString());
|
||
return;
|
||
}
|
||
throw new Error("author fragment failed");
|
||
})
|
||
.catch(function (error) {
|
||
console.error("[AKSRT Comment] Author filter failed:", error);
|
||
window.location.href = url.toString();
|
||
});
|
||
}
|
||
|
||
commentsArea.addEventListener("click", function (e) {
|
||
var target = e.target;
|
||
if (!target || typeof target.closest !== "function") return;
|
||
|
||
// 「只看作者」同时带 comment-orderby,需优先于排序按钮判断
|
||
var authorBtn = target.closest(".btn-only-author");
|
||
if (authorBtn && commentsArea.contains(authorBtn)) {
|
||
e.preventDefault();
|
||
applyAuthorFilter(authorBtn.getAttribute("data-author-only") || "0");
|
||
return;
|
||
}
|
||
|
||
var orderBtn = target.closest(".comment-orderby[data-order]");
|
||
if (orderBtn && commentsArea.contains(orderBtn)) {
|
||
e.preventDefault();
|
||
applyCommentOrder(orderBtn.getAttribute("data-order") || "newest");
|
||
}
|
||
});
|
||
}
|
||
|
||
|
||
/* ====== 数字分页跳页(legacy pag-jump) ====== */
|
||
function jumpToCommentPage(page) {
|
||
page = parseInt(page, 10) || 1;
|
||
var url = new URL(window.location.href);
|
||
url.searchParams.set("cpage", String(page));
|
||
url.hash = "comments";
|
||
window.location.href = url.toString();
|
||
}
|
||
|
||
function initCommentPageJump() {
|
||
document.addEventListener("click", function (e) {
|
||
var jump = e.target.closest ? e.target.closest("#comments .pag-jump") : null;
|
||
if (!jump) return;
|
||
e.preventDefault();
|
||
var input = jump.querySelector(".jump-input");
|
||
if (input) jumpToCommentPage(input.value);
|
||
});
|
||
document.addEventListener("keydown", function (e) {
|
||
if (e.key !== "Enter") return;
|
||
var input = e.target;
|
||
if (!input || !input.classList || !input.classList.contains("jump-input")) return;
|
||
if (!input.closest("#comments .pagenav")) return;
|
||
e.preventDefault();
|
||
jumpToCommentPage(input.value);
|
||
});
|
||
}
|
||
|
||
window.AksrtFrontend.register("aksrt-comment-system", function () { initCommentSystem(); initCommentPageJump(); });
|
||
window.AksrtFrontend.register("aksrt-comment-order", function (root) { initCommentOrder(root); });
|
||
})();
|