/** * AKSRT Comment Actions client * * Single client for per-comment actions via REST aksrt/v1: * like / edit / delete / moderate (approve|hold|spam) / pin * * Comment SUBMISSION is owned by main.js initCommentSystem() (the native * wp-comments-post.php flow, which runs captcha verification, rate limiting and * the moderation pipeline, then re-renders the list through the canonical * server callback). This file deliberately does NOT bind the submit form, so * there is exactly one comment-submit contract. * * Markup contract (rendered by aksrt_comment_callback, identical on first * paint, load-more and post-submit reload): * li.aksrt-comment[data-comment-id] * .aksrt-comment__text (content) * .aksrt-comment__actions * [data-comment-action="like|edit|delete|approve|hold|spam|pin"] * * Depends on: aksrtData.restNonce (wp_rest) + aksrtData.siteUrl. * * @package AKSRT */ (function () { 'use strict'; if (!window.aksrtData) return; var COMMENT_SELECTOR = '.aksrt-comment, .comment'; var CONTENT_SELECTOR = '.aksrt-comment__text'; 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 notify(message, type) { if (typeof window.AksrtToast === 'function') { window.AksrtToast(message, type || 'info'); return; } if (typeof window.aksrtToast === 'function') { window.aksrtToast(message, type || 'info'); return; } if (typeof window.showToast === 'function') { window.showToast(message, type || 'info'); return; } if (type === 'error') { window.alert(message); } } 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 commentId = getCommentId(commentEl); if (!commentId) return; switch (action) { case 'like': handleLike(actionBtn, commentId); break; case 'edit': handleEdit(commentEl); break; case 'save-edit': saveEdit(commentEl, commentId, actionBtn); break; case 'cancel-edit': cancelEdit(commentEl); 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) { notify((result.data && result.data.message) || result.message || '操作失败', 'error'); 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('is-active', active); var icon = btn.querySelector('i'); if (icon) { icon.classList.toggle('fas', active); icon.classList.toggle('far', !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', ''); } } }) .catch(function () { notify('网络错误', 'error'); }) .finally(function () { btn.dataset.busy = ''; }); } function handleEdit(commentEl) { var contentEl = commentEl.querySelector(CONTENT_SELECTOR); if (!contentEl || commentEl.querySelector('.aksrt-comment-edit-form')) return; var temp = document.createElement('div'); temp.innerHTML = contentEl.innerHTML; var originalText = (temp.textContent || temp.innerText || '').trim(); var editForm = document.createElement('div'); editForm.className = 'aksrt-comment-edit-form'; editForm.innerHTML = '' + '