feat(comments): 评论区按 Zibll 1:1 全量复刻

- 评论项/表单/工具栏/筛选/分页/空状态 DOM 全部替换为 zibll 原始类名
  (li.comment、comt-main、comt-meta、list-inline、dropup 工具栏、
  theme-pagination/pagenav、post_ajax_loader 骨架等)
- 移植 zibll main.css L9412–9751 桌面 + 移动端评论样式,
  缺失基础组件(title-theme/dropdown-menu/line-form/tab-nav-theme 等)
  以 #comments 作用域补齐
- 删除全部 aksrt-comment__* 旧类名与旧样式,无兼容层
- JS 选择器对齐 zibll DOM:片段整块替换 #postcomments、骨架加载、
  跳页输入、prepend 插入、addComment onclick 剥离,
  移除 WP comment-reply enqueue 避免双 moveForm
- 表情资源替换为 zibll 全套 gif(内容逐字节一致,git 无差异)
- REST 后端 (CommentActions) 不变

验证:php -l 全部通过;5 个改动 JS 语法校验通过;
node --test tests/widget-system/post-visual-contract.test.cjs 12/12 通过
This commit is contained in:
2026-08-22 13:29:51 +08:00
parent 251fe86527
commit e1f176429b
15 changed files with 1286 additions and 1439 deletions
+2 -132
View File
@@ -1,140 +1,10 @@
/**
* AKSRT Comment Tools
*
* 评论工具栏样式:表情、代码、图片上传、快捷回复。
* 所有选择器均带 .comment- 或 .aksrt-comment- 命名空间。
* 评论内容中的代码块样式。工具栏(表情/代码/图片/快捷回复)的 UI
* 由 assets/css/frontend/comments/shell.css 按 zibll 选择器提供。
*/
/* ========== 评论工具栏 ========== */
.comment-toolbar {
display: flex;
align-items: center;
gap: 4px;
padding: 6px 8px;
margin-bottom: 8px;
background: var(--surface-secondary, #f8f9fa);
border: 1px solid var(--color-line, #e8e8e8);
border-radius: 8px;
}
.comment-toolbar__btn {
display: inline-flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
border: none;
border-radius: 6px;
background: transparent;
color: var(--text-secondary, #666);
font-size: 14px;
cursor: pointer;
transition: background-color 0.15s ease, color 0.15s ease;
}
.comment-toolbar__btn:hover {
background: var(--color-primary-soft, rgba(240, 68, 148, 0.08));
color: var(--color-primary);
}
.comment-toolbar__btn:disabled {
opacity: 0.4;
cursor: not-allowed;
}
.comment-toolbar__separator {
width: 1px;
height: 20px;
margin: 0 4px;
background: var(--color-line, #e8e8e8);
}
/* Server-side toolbar gating (comment_smilie / comment_code / comment_img):
the .comment-toolbar__btn display rule outranks the UA [hidden] rule, so an
attribute-qualified selector is needed to honor the rendered hidden state. */
.comment-toolbar__btn[hidden],
.comment-toolbar__separator[hidden] {
display: none;
}
/* ========== 表情选择器 ========== */
.comment-emoji-picker {
position: absolute;
bottom: 100%;
left: 0;
z-index: 100;
width: 320px;
max-height: 240px;
padding: 12px;
background: var(--surface-page, #fff);
border: 1px solid var(--color-line, #e8e8e8);
border-radius: 8px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
overflow-y: auto;
}
.comment-emoji-picker__grid {
display: grid;
grid-template-columns: repeat(8, 1fr);
gap: 4px;
}
.comment-emoji-picker__item {
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
border: none;
border-radius: 4px;
background: transparent;
font-size: 18px;
cursor: pointer;
transition: background-color 0.1s ease;
}
.comment-emoji-picker__item:hover {
background: var(--color-primary-soft, rgba(240, 68, 148, 0.08));
}
/* ========== 快捷回复 ========== */
.comment-quick-reply {
padding: 8px 12px;
margin-top: 8px;
background: var(--surface-secondary, #f8f9fa);
border: 1px solid var(--color-line, #e8e8e8);
border-radius: 8px;
}
.comment-quick-reply__title {
font-size: 12px;
font-weight: 600;
color: var(--text-secondary, #666);
}
.comment-quick-reply__templates {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-top: 6px;
}
.comment-quick-reply__template {
padding: 4px 10px;
border: 1px solid var(--color-line, #e8e8e8);
border-radius: 16px;
background: var(--surface-page, #fff);
font-size: 12px;
color: var(--text-secondary, #666);
cursor: pointer;
transition: border-color 0.15s ease, color 0.15s ease;
}
.comment-quick-reply__template:hover {
border-color: var(--color-primary);
color: var(--color-primary);
}
/* ========== 评论代码块 ========== */
.comment-form textarea code,
.comment-content code {
+171 -108
View File
@@ -1,112 +1,175 @@
/* Zibll 1:1 FixedInput / virtual-input / item chrome */
.virtual-input { display: none; }
@media (max-width: 767.98px) {
.virtual-input {
display: flex; align-items: center; gap: 10px;
padding: 10px 12px; margin-bottom: 12px; border-radius: 999px;
background: var(--surface-1, #fff);
box-shadow: var(--shadow-sm, 0 1px 4px rgba(0,0,0,.06));
cursor: pointer;
}
.virtual-input .avatar-img { width: 32px; height: 32px; border-radius: 50%; }
.virtual-input .simulation { flex: 1; color: var(--color-ink-4, #999); font-size: 13px; }
#respond.mobile-fixed {
position: fixed; left: 0; right: 0; bottom: 0; z-index: 1050;
background: var(--surface-1, #fff);
border-radius: 12px 12px 0 0;
box-shadow: 0 -8px 28px rgba(0,0,0,.12);
padding: 12px 14px max(12px, env(safe-area-inset-bottom));
transform: translateY(110%); transition: transform .25s ease;
max-height: 85vh; overflow: auto;
}
#respond.mobile-fixed.show { transform: translateY(0); }
#respond.mobile-fixed .fixed-body {
position: fixed; inset: 0; background: rgba(0,0,0,.35); z-index: -1;
opacity: 0; pointer-events: none; transition: opacity .2s ease;
}
#respond.mobile-fixed.show .fixed-body { opacity: 1; pointer-events: auto; }
#respond.mobile-fixed .comt-title { display: none; }
}
.comment-header .author-box { display: flex; align-items: center; gap: 8px; width: 100%; }
.comment-header .author-box name,
.comment-header .author-box .flex1 { flex: 1; min-width: 0; }
/* Keep name + level badge on one line; clamp the name so the badge never wraps. */
.comment-header .author-box name { flex-wrap: nowrap; }
.comment-header .author-box .aksrt-comment__author { max-width: 14em; }
.comment-header .aksrt-comment__like,
.comment-header .action-comment-like {
margin-left: auto; display: inline-flex; align-items: center; gap: 4px;
color: var(--color-ink-3, #888); text-decoration: none; font-size: 13px;
}
.comment-header .aksrt-comment__like.is-active { color: var(--color-primary, #2060ef); }
.comt-meta {
display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
font-size: 12px; margin-top: 6px;
}
.comt-meta .reply-link a, .comt-meta .comment-reply-link { color: var(--color-ink-3, #777); }
.comment-action-dropdown .dropdown-menu { min-width: 140px; padding: 6px 0; }
.comment-action-dropdown .dropdown-menu a {
display: block; padding: 6px 14px; color: var(--color-ink, #333);
text-decoration: none; font-size: 13px;
}
.comment-action-dropdown .dropdown-menu a:hover { background: var(--surface-2, #f5f5f5); }
.smilie-icon { width: 30px; height: 30px; vertical-align: -8px; display: inline-block; }
.comment-inline-img, .comment-content .box-img {
max-width: 260px; max-height: 350px; border-radius: 6px; display: block; margin: 6px 0;
}
.comment-code {
background: var(--surface-2, #f6f8fa); padding: 10px 12px; border-radius: 6px;
overflow: auto; font-size: 12px;
}
.commentlist .children { margin-left: 86px; padding-left: 0; list-style: none; }
.commentlist .children .children { margin-left: 23px; }
.commentlist .children .comt-avatar,
.commentlist .children .avatar-img.comt-avatar { width: 26px !important; height: 26px !important; }
.input-expand-wrap { display: inline-block; position: relative; }
.input-expand-wrap .dropdown-menu,
.input-expand-wrap .dropdown-smilie {
display: none; position: absolute; bottom: 100%; left: 0; z-index: 20;
background: var(--surface-1, #fff); box-shadow: 0 6px 24px rgba(0,0,0,.12);
border-radius: 8px; padding: 8px;
}
.input-expand-wrap.open > .dropdown-menu,
.input-expand-wrap.open .dropdown-smilie,
.dropup.open > .dropdown-menu { display: block; }
.dropdown-smilie {
display: grid; grid-template-columns: repeat(8, 1fr); gap: 4px;
max-width: 280px; max-height: 200px; overflow: auto;
}
.dropdown-smilie a img { width: 28px; height: 28px; }
.quick-reply-item {
display: block; padding: 6px 10px; color: var(--color-ink, #333);
text-decoration: none; font-size: 13px;
}
.quick-reply-item:hover { background: var(--surface-2, #f5f5f5); }
.comt-ctrl { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 8px; }
.comt-tips-left { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; flex: 1; }
.comt-tips-right { margin-left: auto; display: flex; align-items: center; gap: 8px; }
#comments .comt-title { width: 90px; }
#comments .comt-title .comt-avatar img,
#comments .comt-avatar .avatar-img { width: 60px; height: 60px; border-radius: 50%; }
#comments .comt-box #comment { min-height: 88px; resize: vertical; }
@media (min-width: 768px) { .hide-pc { display: none !important; } }
/* ============================================================
* AKSRT Comments — Zibll 1:1 移动端 + FixedInput / virtual-input
*
* 移动端规则来源:zibll/css/main.css 移动端媒体查询中的评论段。
* ============================================================ */
/* IP geo badges */
.comt-meta .comment-city-badge,
.comt-meta .aksrt-ip-geo-badge {
margin-left: 0.35em;
vertical-align: middle;
.virtual-input {
display: none;
}
.aksrt-author-hero__identity .aksrt-ip-geo-badge,
.uc-header__meta .aksrt-ip-geo-badge,
.article-avatar .aksrt-ip-geo-badge {
margin: 2px 0;
vertical-align: middle;
/* 移动端虚拟输入条 + 吸底表单(FixedInput) */
@media (max-width: 767.98px) {
.virtual-input {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 12px;
margin-bottom: 12px;
border-radius: 999px;
background: var(--surface-1, #fff);
box-shadow: var(--shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));
cursor: pointer;
}
.virtual-input .avatar,
.virtual-input .avatar-img {
width: 32px;
height: 32px;
border-radius: 50%;
}
.virtual-input .simulation {
flex: 1;
color: var(--color-ink-4, #999);
font-size: 13px;
}
#respond.mobile-fixed {
position: fixed;
left: 0;
right: 0;
bottom: 0;
z-index: 1050;
background: var(--surface-1, #fff);
border-radius: 12px 12px 0 0;
box-shadow: 0 -8px 28px rgba(0, 0, 0, .12);
padding: 12px 14px max(12px, env(safe-area-inset-bottom));
transform: translateY(110%);
transition: transform .25s ease;
max-height: 85vh;
overflow: auto;
}
#respond.mobile-fixed.show {
transform: translateY(0);
}
#respond.mobile-fixed .fixed-body {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, .35);
z-index: -1;
opacity: 0;
pointer-events: none;
transition: opacity .2s ease;
}
#respond.mobile-fixed.show .fixed-body {
opacity: 1;
pointer-events: auto;
}
#respond.mobile-fixed .comt-title {
display: none;
}
/* ---- zibll 移动端评论规则 ---- */
#comments .comt-title {
display: none;
}
#comments .comt-box {
width: 100%;
padding: 0;
}
#comments .list-inline {
padding: 15px 0;
margin: 0;
}
#comments .comment-signarea h3 {
font-size: 13px;
}
#comments .comt-tips-left .but svg,
#comments .comt-tips-left .but .fa {
margin: 0;
}
#comments .hide-sm {
display: none !important;
}
#comments .btn-input-expand {
width: 31px;
padding: 0;
height: 31px;
line-height: 31px;
}
#postcomments .comment-header {
font-size: 14px;
}
#postcomments .comt-meta {
font-size: 12px;
}
#postcomments .comment .list-inline > li {
padding: 0;
}
#postcomments .comment .list-inline > li + li {
padding-left: 10px;
}
#postcomments .avatar-img {
--this-size: 36px;
margin-right: 10px;
}
#postcomments .commentlist > .comment > .list-inline .comment-footer {
margin-left: 45px;
margin-top: -15px;
}
#postcomments .children {
margin-left: 0;
}
#postcomments .children .children {
margin-left: 13px;
}
#postcomments .children .list-inline {
padding: 15px;
}
#comments .pagenav a,
#comments .pagination ul > li {
display: none;
}
#comments .pagenav a.next,
#comments .pagenav a.prev {
display: inline-block;
}
#comments .pagenav .page-numbers {
font-size: 12px;
margin: 2px;
min-width: 28px;
}
#postcomments .post_ajax_loader .ml20 {
margin-left: 5px;
}
}
.aksrt-author-hero__identity {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.35rem;
margin-top: 0.35rem;
@media (min-width: 768px) {
.hide-pc {
display: none !important;
}
}
File diff suppressed because it is too large Load Diff
-23
View File
@@ -56,29 +56,6 @@
font-size: 12px;
}
/* 评论空状态 */
.comments-empty {
text-align: center;
padding: 40px 20px;
}
.comments-empty__icon {
font-size: 48px;
color: var(--surface-3, #e8e8e8);
margin-bottom: 12px;
}
.comments-empty__text {
font-size: 14px;
color: var(--color-ink-3, #777);
margin-bottom: 4px;
}
.comments-empty__hint {
font-size: 12px;
color: var(--color-ink-4, #999);
}
/* 搜索空状态 */
.search-empty {
text-align: center;
+23 -25
View File
@@ -5,11 +5,11 @@
* Edit uses moveForm (#respond) via comment-move-form.js — not inline textarea.
* Submit owned by assets/js/core/comments.js (single submit contract).
*
* Markup (aksrt_comment_callback):
* li.aksrt-comment[data-comment-id]
* .comment-header .aksrt-comment__like[data-comment-action=like]
* Markup (aksrt_comment_callback, zibll DOM):
* li.comment#comment-{id}
* .comment-header .action-comment-like[data-comment-action=like] > count
* .comment-content#comment-content-{id}
* .comt-meta [data-comment-action=pin|approve|hold|spam|delete]
* .comt-meta [data-comment-action=pin|approve|hold|delete]
*
* @package AKSRT
*/
@@ -19,8 +19,8 @@
if (!window.aksrtData) return;
var COMMENT_SELECTOR = '.aksrt-comment, .comment';
var CONTENT_SELECTOR = '.aksrt-comment__text, .comment-content';
var COMMENT_SELECTOR = 'li.comment';
var CONTENT_SELECTOR = '.comment-content';
var REST_BASE = (aksrtData.siteUrl || '').replace(/\/$/, '') + '/wp-json/aksrt/v1';
var REST_NONCE = aksrtData.restNonce || '';
@@ -48,6 +48,10 @@
var commentEl = actionBtn.closest(COMMENT_SELECTOR);
if (!commentEl) return;
// 操作后收起 ⋮ 菜单
var openMenu = actionBtn.closest('span.dropdown.open');
if (openMenu) openMenu.classList.remove('open');
var commentId = getCommentId(commentEl);
if (!commentId) return;
@@ -75,14 +79,9 @@
var count = (result.data && result.data.count) || 0;
btn.setAttribute('data-active', active ? '1' : '0');
btn.setAttribute('aria-pressed', active ? 'true' : 'false');
btn.classList.toggle('is-active', active);
var icon = btn.querySelector('i');
if (icon) { icon.classList.toggle('fa', active); icon.classList.toggle('fa', !active); }
var countEl = btn.querySelector('.aksrt-comment__like-count');
if (countEl) {
countEl.textContent = String(count);
if (count > 0) { countEl.removeAttribute('hidden'); } else { countEl.setAttribute('hidden', ''); }
}
btn.classList.toggle('actived', active);
var countEl = btn.querySelector('count');
if (countEl) countEl.textContent = String(count);
})
.catch(function () { notyf('网络错误', 'danger'); })
.finally(function () { btn.dataset.busy = ''; });
@@ -103,7 +102,7 @@
});
setTimeout(function () {
commentEl.remove();
var countEl = document.querySelector('.comments-count');
var countEl = document.querySelector('#comments .title-theme small');
if (countEl) {
var m = (countEl.textContent || '').match(/(\d+)/);
if (m) {
@@ -134,8 +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 fas fa-thumbtack" aria-hidden="true"></i> ' + (pinned ? '取消置顶' : '置顶');
commentEl.classList.toggle('aksrt-comment--pinned', pinned);
btn.innerHTML = '<i class="fa fa-thumbtack mr10 fa-fw" aria-hidden="true"></i>' + (pinned ? '取消置顶' : '设置置顶');
syncPinnedBadge(commentEl, pinned);
notyf(result.message || (pinned ? '评论已置顶。' : '已取消置顶。'), 'success');
})
@@ -143,15 +141,15 @@
}
function syncPinnedBadge(commentEl, pinned) {
var header = commentEl.querySelector('.aksrt-comment__header, .comment-header');
if (!header) return;
var badge = header.querySelector('.aksrt-comment__badge--pinned');
var name = commentEl.querySelector('.comment-header name');
if (!name) return;
var badge = name.querySelector('badge.badge-topping');
if (pinned && !badge) {
badge = document.createElement('span');
badge.className = 'aksrt-comment__badge aksrt-comment__badge--pinned';
badge.innerHTML = '<i class="fa fas fa-thumbtack" aria-hidden="true"></i> 置顶';
var time = header.querySelector('.aksrt-comment__time');
header.insertBefore(badge, time || null);
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>';
name.insertBefore(badge, name.firstChild);
} else if (!pinned && badge) {
badge.remove();
}
+4 -4
View File
@@ -49,7 +49,7 @@
}
if (!key) return;
insertAtCursor(findTextarea(sm), '[g=' + key + ']');
var wrap = sm.closest('.dropup, .input-expand-wrap');
var wrap = sm.closest('span.dropup');
if (wrap) wrap.classList.remove('open');
return;
}
@@ -66,7 +66,7 @@
}
insertAtCursor(findTextarea(codeBtn), '[code]\n' + code + '\n[/code]\n');
if (ta) ta.value = '';
var w = codeBtn.closest('.dropup, .input-expand-wrap');
var w = codeBtn.closest('span.dropup');
if (w) w.classList.remove('open');
return;
}
@@ -83,7 +83,7 @@
}
insertAtCursor(findTextarea(imgBtn), '[img=' + url + ']');
if (input) input.value = '';
var iw = imgBtn.closest('.dropup, .input-expand-wrap');
var iw = imgBtn.closest('span.dropup');
if (iw) iw.classList.remove('open');
return;
}
@@ -117,7 +117,7 @@
e.preventDefault();
var phrase = q.getAttribute('data-text') || q.textContent || '';
insertAtCursor(findTextarea(q), phrase);
var qw = q.closest('.dropup, .input-expand-wrap');
var qw = q.closest('span.dropup');
if (qw) qw.classList.remove('open');
}
});
+12 -13
View File
@@ -145,7 +145,9 @@
if (submit) submit.disabled = false;
});
} else {
setActionText('回复评论');
var nameEl = comm ? comm.querySelector('.comment-header name') : null;
var author = nameEl ? (nameEl.textContent || '').trim() : '';
setActionText(author ? ('回复 @' + author) : '回复评论');
ensureEditField(respond, 0);
if (textarea) {
textarea.focus();
@@ -195,25 +197,22 @@
}
});
// Dropup toggles (guest / expand).
// Dropup / dropdown toggles (guest info, expand toolbar, action menu).
document.addEventListener('click', function (e) {
var t = e.target && e.target.closest ? e.target.closest('[data-toggle-class="open"]') : null;
var t = e.target && e.target.closest ? e.target.closest('[data-toggle-class="open"], span.dropup > a.but, [data-toggle="dropdown"]') : null;
if (!t) return;
var targetSel = t.getAttribute('data-target');
if (!targetSel) return;
var wrap = t.closest('span.dropup, span.dropdown');
if (!wrap) return;
// 点击已在打开的下拉内部(表情/快捷项等)不切换
if (wrap.classList.contains('open') && t.parentElement !== wrap) return;
e.preventDefault();
var wrap = t.closest('.dropup, .input-expand-wrap, #comment-user-info') || t.parentElement;
var panel = targetSel.charAt(0) === '#' || targetSel.charAt(0) === '.'
? (wrap && wrap.querySelector(targetSel)) || document.querySelector(targetSel)
: null;
if (wrap) wrap.classList.toggle('open');
if (panel && panel !== wrap) panel.classList.toggle('open');
wrap.classList.toggle('open');
});
// Close dropups on outside click.
document.addEventListener('click', function (e) {
if (e.target.closest && e.target.closest('.dropup, .input-expand-wrap, [data-toggle-class="open"]')) return;
document.querySelectorAll('.dropup.open, .input-expand-wrap.open, #comment-user-info.open').forEach(function (n) {
if (e.target.closest && e.target.closest('span.dropup.open, span.dropdown.open')) return;
document.querySelectorAll('span.dropup.open, span.dropdown.open').forEach(function (n) {
n.classList.remove('open');
});
});
+72 -107
View File
@@ -97,13 +97,13 @@
}
function updateCommentCount(delta) {
var countEl = document.querySelector('.comments-count');
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 = '共 ' + nextCount + ' 条';
countEl.textContent = text.replace(match[1], String(nextCount));
}
function handleResponse(responseText, statusCode) {
try {
@@ -316,9 +316,9 @@
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 + ', [data-comment-id="' + parentId + '"]');
var parentComment = document.querySelector('#comment-' + parentId);
if (parentComment) {
var children = parentComment.querySelector('.children');
var children = parentComment.querySelector(':scope > .children');
if (!children) {
children = document.createElement('ol');
children.className = 'children';
@@ -354,8 +354,15 @@
}
function prependToCommentList(el) {
var list = document.querySelector('.commentlist, #comment-list > ol, #comment-list');
if (list) list.insertBefore(el, list.firstChild);
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() {
@@ -471,66 +478,27 @@
function getCurrentAuthorOnly() {
var url = new URL(window.location.href);
if (url.searchParams.get("aksrt_author_only") === "1") return true;
var btn = document.querySelector("#comments .comment-author-filter");
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) return;
if (!commentsArea || !data || !data.html) return;
if (data.filter_html) {
var currentFilter = commentsArea.querySelector(".comment-filter");
var temp = document.createElement("div");
temp.innerHTML = data.filter_html;
var newFilter = temp.firstElementChild;
if (newFilter) {
if (currentFilter) currentFilter.replaceWith(newFilter);
else {
var listAnchor = commentsArea.querySelector("#postcomments, #comment-list");
if (listAnchor && listAnchor.parentNode) {
listAnchor.parentNode.insertBefore(newFilter, listAnchor);
}
}
}
}
// 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");
var currentList = commentsArea.querySelector("#comment-list");
var currentEmpty = commentsArea.querySelector(".comments-empty");
var tempList = document.createElement("div");
tempList.innerHTML = data.html || "";
var newListWrap = tempList.querySelector("#postcomments");
var newEmpty = tempList.querySelector(".comments-empty");
if (newListWrap) {
if (currentListWrap) currentListWrap.replaceWith(newListWrap);
else if (currentList) currentList.replaceWith(newListWrap);
else commentsArea.appendChild(newListWrap);
if (currentEmpty) currentEmpty.remove();
} else if (newEmpty) {
if (currentListWrap) currentListWrap.remove();
if (currentList) currentList.remove();
if (currentEmpty) currentEmpty.replaceWith(newEmpty);
else commentsArea.appendChild(newEmpty);
if (currentListWrap) {
currentListWrap.replaceWith(newListWrap);
} else {
commentsArea.appendChild(newListWrap);
}
var currentPagination = commentsArea.querySelector(".aksrt-comment-pagination, .comment-navigation, .pagenav.ajax-pag");
if (data.pagination_html) {
var ptemp = document.createElement("div");
ptemp.innerHTML = data.pagination_html;
var newPag = ptemp.firstElementChild;
if (newPag) {
if (currentPagination) currentPagination.replaceWith(newPag);
else {
var list = commentsArea.querySelector("#postcomments, #comment-list");
if (list && list.parentNode) list.parentNode.insertBefore(newPag, list.nextSibling);
}
}
} else if (currentPagination) {
currentPagination.remove();
}
var currentCount = commentsArea.querySelector(".comments-count");
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") {
@@ -562,20 +530,30 @@
}
/* ====== 评论列表动态刷新 ====== */
function showListLoading(commentsArea) {
var list = commentsArea.querySelector(".commentlist");
if (!list) return;
// 保留筛选栏,清空条目并显示 zibll 骨架
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');
var listContainer = document.getElementById('comment-list');
if (!commentsArea && !listContainer) {
if (!commentsArea) {
window.location.reload();
return;
}
if (listContainer) {
listContainer.innerHTML = '<li class="comment-loading-skeleton">' +
'<div class="aksrt-comment"><div class="aksrt-comment__body">' +
'<div style="height:60px;background:#f0f0f0;border-radius:8px;margin-bottom:10px;animation:pulse 1.5s ease-in-out infinite;"></div>' +
'<div style="height:20px;width:70%;background:#f0f0f0;border-radius:4px;animation:pulse 1.5s ease-in-out infinite;"></div>' +
'</div></div></li>';
}
showListLoading(commentsArea);
fetchCommentFragment({
order: getCurrentCommentOrder(),
@@ -583,7 +561,7 @@
page: 1
}).then(function (json) {
if (json && json.success && json.data) {
applyFragmentPayload(commentsArea || document, json.data, null);
applyFragmentPayload(commentsArea, json.data, null);
return;
}
throw new Error('fragment failed');
@@ -622,13 +600,7 @@
commentsArea.dataset.orderInit = "1";
function renderLoadingState() {
var listContainer = commentsArea.querySelector("#comment-list");
if (!listContainer) return;
listContainer.innerHTML = '<li class="comment-loading-skeleton">' +
'<div class="aksrt-comment"><div class="aksrt-comment__body">' +
'<div style="height:60px;background:#f0f0f0;border-radius:8px;margin-bottom:10px;animation:pulse 1.5s ease-in-out infinite;"></div>' +
'<div style="height:20px;width:70%;background:#f0f0f0;border-radius:4px;animation:pulse 1.5s ease-in-out infinite;"></div>' +
'</div></div></li>';
showListLoading(commentsArea);
}
function applyCommentOrder(order) {
if (order !== "newest" && order !== "oldest" && order !== "hottest") {
@@ -685,7 +657,7 @@
if (!target || typeof target.closest !== "function") return;
// 「只看作者」同时带 comment-orderby,需优先于排序按钮判断
var authorBtn = target.closest(".comment-author-filter");
var authorBtn = target.closest(".btn-only-author");
if (authorBtn && commentsArea.contains(authorBtn)) {
e.preventDefault();
applyAuthorFilter(authorBtn.getAttribute("data-author-only") || "0");
@@ -701,40 +673,33 @@
}
function initGuestFields() {
var root = document.getElementById("comments") || document;
root.querySelectorAll("[data-aksrt-guest-toggle]").forEach(function (btn) {
if (btn.dataset.aksrtGuestBound === "1") return;
btn.dataset.aksrtGuestBound = "1";
var wrap = btn.closest(".comment-form__guest");
var fields = wrap ? wrap.querySelector("[data-aksrt-guest-fields]") : null;
if (!fields) return;
btn.addEventListener("click", function (e) {
e.preventDefault();
var open = btn.getAttribute("aria-expanded") === "true";
btn.setAttribute("aria-expanded", open ? "false" : "true");
if (open) {
fields.setAttribute("hidden", "");
fields.classList.remove("is-open");
} else {
fields.removeAttribute("hidden");
fields.classList.add("is-open");
var first = fields.querySelector("input");
if (first) first.focus();
}
});
// Auto-open if browser restored values or validation fails later.
var form = btn.closest("form");
if (form) {
form.addEventListener("invalid", function () {
fields.removeAttribute("hidden");
fields.classList.add("is-open");
btn.setAttribute("aria-expanded", "true");
}, true);
}
/* ====== 数字分页跳页(zibll 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(); initGuestFields(); });
window.AksrtFrontend.register("aksrt-comment-system", function () { initCommentSystem(); initCommentPageJump(); });
window.AksrtFrontend.register("aksrt-comment-order", function (root) { initCommentOrder(root); });
})();
+4 -2
View File
@@ -42,8 +42,8 @@
target = target.previousElementSibling;
}
if (isComment) {
var commentList = document.getElementById("comment-list") ||
(container.parentElement && container.parentElement.querySelector("#comment-list, .commentlist, ol.commentlist"));
var commentList = container.closest("#comment-list, .commentlist, ol.commentlist") ||
document.getElementById("comment-list");
if (commentList) target = commentList;
}
if (!target && container.parentElement) {
@@ -167,6 +167,8 @@
while (newItems.length > 0) {
if (homepagePanel && container.parentNode === target) {
target.insertBefore(newItems[0], container);
} else if (container.parentNode === target) {
target.insertBefore(newItems[0], container);
} else {
target.appendChild(newItems[0]);
}