/** * AKSRT Comment Actions client * * REST aksrt/v1: like / delete / moderate / pin. * 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, legacy 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|delete] * * @package AKSRT */ (function () { 'use strict'; if (!window.aksrtData) return; 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 || ''; function restPost(endpoint, body) { return fetch(REST_BASE + endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': REST_NONCE }, body: JSON.stringify(body), credentials: 'same-origin' }).then(function (r) { return r.json(); }); } function getCommentId(el) { return parseInt(el.getAttribute('data-comment-id') || (el.id || '').replace('comment-', ''), 10) || 0; } // ── Comment actions (event delegation) ─────────────────────────── document.addEventListener('click', function (e) { var actionBtn = e.target.closest('[data-comment-action]'); if (!actionBtn) return; var action = actionBtn.getAttribute('data-comment-action'); 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; // edit is handled by comment-move-form.js (moveForm into #respond). switch (action) { case 'like': handleLike(actionBtn, commentId); break; case 'edit': break; case 'delete': handleDelete(commentEl, commentId); break; case 'pin': handlePin(commentEl, actionBtn, commentId); break; case 'approve': case 'hold': case 'spam': handleModerate(commentEl, commentId, action); break; } }); function handleLike(btn, commentId) { if (btn.dataset.busy === '1') return; btn.dataset.busy = '1'; var nextActive = btn.getAttribute('data-active') !== '1'; restPost('/comment/like', { comment_id: commentId, active: nextActive }) .then(function (result) { if (!result.success) { notyf((result.data && result.data.message) || result.message || '操作失败', 'danger'); return; } var active = !!(result.data && result.data.active); 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('actived', active); var countEl = btn.querySelector('count'); if (countEl) countEl.textContent = String(count); }) .catch(function () { notyf('网络错误', 'danger'); }) .finally(function () { btn.dataset.busy = ''; }); } function handleDelete(commentEl, commentId) { var msg = (window.aksrt && aksrt.__) ? aksrt.__('comment_confirm_delete', '确定要删除这条评论吗?') : '确定要删除这条评论吗?'; var doDelete = function () { restPost('/comment/delete', { comment_id: commentId }) .then(function (result) { if (result.success) { commentEl.style.transition = 'opacity 0.3s, max-height 0.3s'; commentEl.style.maxHeight = commentEl.scrollHeight + 'px'; requestAnimationFrame(function () { commentEl.style.opacity = '0'; commentEl.style.maxHeight = '0'; commentEl.style.overflow = 'hidden'; }); setTimeout(function () { commentEl.remove(); var countEl = document.querySelector('#comments .title-theme small'); if (countEl) { var m = (countEl.textContent || '').match(/(\d+)/); if (m) { var n = Math.max(0, parseInt(m[1], 10) - 1); countEl.textContent = (countEl.textContent || '').replace(m[1], String(n)); } } }, 300); } else { notyf((result.data && result.data.message) || result.message || '删除失败', 'danger'); } }) .catch(function () { notyf('网络错误', 'danger'); }); }; if (window.aksrt && aksrt.confirm) { aksrt.confirm(msg).then(function (ok) { if (ok) doDelete(); }); } else if (window.confirm(msg)) { doDelete(); } } function handlePin(commentEl, btn, commentId) { var nextPinned = btn.getAttribute('data-pinned') !== '1'; restPost('/comment/pin', { comment_id: commentId, pinned: nextPinned }) .then(function (result) { 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 = '' + (pinned ? '取消置顶' : '设置置顶'); syncPinnedBadge(commentEl, pinned); notyf(result.message || (pinned ? '评论已置顶。' : '已取消置顶。'), 'success'); }) .catch(function () { notyf('网络错误', 'danger'); }); } function syncPinnedBadge(commentEl, pinned) { var name = commentEl.querySelector('.comment-header name'); if (!name) return; var badge = name.querySelector('badge.badge-topping'); if (pinned && !badge) { badge = document.createElement('badge'); badge.className = 'badge-topping jb-blue mr6 flex0'; badge.title = '置顶评论'; badge.innerHTML = ''; name.insertBefore(badge, name.firstChild); } else if (!pinned && badge) { badge.remove(); } } function handleModerate(commentEl, commentId, action) { restPost('/comment/moderate', { comment_id: commentId, status: action }) .then(function (result) { if (result.success) { commentEl.setAttribute('data-comment-status', result.data.status === 'approved' ? '1' : (result.data.status === 'spam' ? 'spam' : '0')); commentEl.style.opacity = '0.6'; setTimeout(function () { commentEl.style.opacity = '1'; }, 400); if (action === 'approve') { var note = commentEl.querySelector('.awaiting-moderation'); if (note) note.remove(); } notyf(result.message || '操作成功。', 'success'); } else { notyf((result.data && result.data.message) || result.message || '操作失败', 'danger'); } }) .catch(function () { notyf('网络错误', 'danger'); }); } })();