- Order_Repository: status note merges into JSON as status_note instead of wiping coupon/topic_pay meta - Extract aksrt_burn_order_coupon / aksrt_coupon_usage_exists for content + topic - Money plate follow (incl. VIP free) always opens multi-gateway cashier for 0-order ledger
1560 lines
68 KiB
JavaScript
1560 lines
68 KiB
JavaScript
(function () {
|
||
'use strict';
|
||
|
||
var rootData = window.aksrtData || {};
|
||
var restRoot = (function () {
|
||
var siteUrl = String(rootData.siteUrl || '/').replace(/\/+$/, '');
|
||
return siteUrl + '/wp-json/aksrt/v1';
|
||
})();
|
||
|
||
function request(path, options) {
|
||
var config = options || {};
|
||
var headers = config.headers || {};
|
||
|
||
return fetch(restRoot + path, {
|
||
method: config.method || 'GET',
|
||
headers: Object.assign({
|
||
'Content-Type': 'application/json',
|
||
'X-WP-Nonce': rootData.restNonce || '',
|
||
}, headers),
|
||
body: config.body || null,
|
||
credentials: 'same-origin',
|
||
}).then(function (response) {
|
||
return response.json().catch(function () {
|
||
return {};
|
||
}).then(function (payload) {
|
||
if (!response.ok || payload.success === false) {
|
||
throw new Error(payload.message || ('HTTP ' + response.status));
|
||
}
|
||
return payload;
|
||
});
|
||
});
|
||
}
|
||
|
||
function setFeedback(node, text, state) {
|
||
if (!node) {
|
||
return;
|
||
}
|
||
|
||
node.textContent = text || '';
|
||
node.classList.remove('is-success', 'is-error', 'is-loading');
|
||
if (state) {
|
||
node.classList.add(state);
|
||
}
|
||
}
|
||
|
||
function bindComposeToolbar(form) {
|
||
// §7.4: toolbar replaced by wp_editor TinyMCE — no-op stub kept for boot() compat
|
||
}
|
||
|
||
function insertTextAtCursor(textarea, text, after, start, end) {
|
||
var value = textarea.value;
|
||
textarea.value = value.substring(0, start) + text + (after || '') + value.substring(end);
|
||
textarea.focus();
|
||
}
|
||
|
||
function askUrlInline(anchor, placeholder, callback) {
|
||
// kept for potential quicktags fallback
|
||
var existing = document.querySelector('.aksrt-inline-url-input');
|
||
if (existing) existing.remove();
|
||
|
||
var input = document.createElement('input');
|
||
input.type = 'url';
|
||
input.className = 'aksrt-inline-url-input';
|
||
input.placeholder = placeholder || 'https://';
|
||
input.value = 'https://';
|
||
input.style.cssText = 'display:block;width:100%;max-width:320px;margin:4px 0;padding:6px 10px;border:1px solid #dce3ec;border-radius:8px;font-size:13px;';
|
||
|
||
var parent = anchor.parentElement;
|
||
parent.insertBefore(input, anchor.nextSibling);
|
||
input.focus();
|
||
input.select();
|
||
|
||
function done() {
|
||
var val = input.value.trim();
|
||
input.remove();
|
||
callback(val);
|
||
}
|
||
|
||
input.addEventListener('keydown', function (e) {
|
||
if (e.key === 'Enter') { e.preventDefault(); done(); }
|
||
if (e.key === 'Escape') { input.remove(); callback(''); }
|
||
});
|
||
input.addEventListener('blur', function () { done(); });
|
||
}
|
||
|
||
function bindComposeVoteToggle(form) {
|
||
var toggle = form.querySelector('#compose-vote-enabled');
|
||
var fields = form.querySelector('.aksrt-forum-compose__vote-fields');
|
||
if (!toggle || !fields) {
|
||
return;
|
||
}
|
||
|
||
function sync() {
|
||
fields.hidden = !toggle.checked;
|
||
}
|
||
|
||
toggle.addEventListener('change', sync);
|
||
sync();
|
||
}
|
||
|
||
function getEditorContent() {
|
||
if (typeof tinymce !== 'undefined') {
|
||
var editor = tinymce.get('compose-content');
|
||
if (editor && !editor.isHidden()) {
|
||
return editor.getContent();
|
||
}
|
||
}
|
||
var textarea = document.querySelector('#compose-content');
|
||
return textarea ? textarea.value : '';
|
||
}
|
||
|
||
function bindComposeDraft(form) {
|
||
var draftButton = form.querySelector('#compose-draft');
|
||
var feedback = form.querySelector('.js-aksrt-action-feedback');
|
||
var ajaxUrl = form.getAttribute('data-ajax');
|
||
var nonce = form.getAttribute('data-nonce');
|
||
|
||
if (!draftButton || !ajaxUrl || !nonce) {
|
||
return;
|
||
}
|
||
|
||
draftButton.addEventListener('click', function () {
|
||
draftButton.disabled = true;
|
||
setFeedback(feedback, '正在保存草稿…', 'is-loading');
|
||
|
||
var data = new FormData(form);
|
||
data.set('content', getEditorContent());
|
||
data.append('action', 'aksrt_forum_save_draft');
|
||
data.append('_nonce', nonce);
|
||
|
||
var draftId = form.getAttribute('data-draft-id') || '0';
|
||
if (draftId && draftId !== '0') {
|
||
data.append('draft_id', draftId);
|
||
}
|
||
|
||
fetch(ajaxUrl, {
|
||
method: 'POST',
|
||
body: data,
|
||
credentials: 'same-origin',
|
||
}).then(function (r) { return r.json(); }).then(function (payload) {
|
||
if (!payload.success) {
|
||
throw new Error((payload.data && payload.data.message) || '保存失败');
|
||
}
|
||
if (payload.data && payload.data.post_id) {
|
||
form.setAttribute('data-draft-id', String(payload.data.post_id));
|
||
}
|
||
setFeedback(feedback, payload.data.message || '草稿已保存', 'is-success');
|
||
draftButton.disabled = false;
|
||
}).catch(function (error) {
|
||
setFeedback(feedback, error.message || '保存失败', 'is-error');
|
||
draftButton.disabled = false;
|
||
});
|
||
});
|
||
}
|
||
|
||
function bindComposeSubmit(form) {
|
||
var submitButton = form.querySelector('#compose-submit');
|
||
var feedback = form.querySelector('.js-aksrt-action-feedback');
|
||
var ajaxUrl = form.getAttribute('data-ajax');
|
||
var nonce = form.getAttribute('data-nonce');
|
||
|
||
if (!submitButton || !ajaxUrl || !nonce) {
|
||
return;
|
||
}
|
||
|
||
form.addEventListener('submit', function (event) {
|
||
event.preventDefault();
|
||
|
||
var board = form.querySelector('#compose-board') || form.querySelector('[name="board_id"]');
|
||
var title = form.querySelector('#compose-title');
|
||
var content = getEditorContent();
|
||
|
||
if (!board || !board.value || !title || !title.value.trim() || !content.trim()) {
|
||
setFeedback(feedback, '请填写版块、标题和主题内容。', 'is-error');
|
||
return;
|
||
}
|
||
|
||
submitButton.disabled = true;
|
||
setFeedback(feedback, '正在提交主题…', 'is-loading');
|
||
|
||
var data = new FormData(form);
|
||
data.set('content', content);
|
||
data.append('action', 'aksrt_forum_create_topic');
|
||
data.append('_nonce', nonce);
|
||
|
||
var draftId = form.getAttribute('data-draft-id') || '0';
|
||
if (draftId && draftId !== '0') {
|
||
data.append('draft_id', draftId);
|
||
}
|
||
|
||
fetch(ajaxUrl, {
|
||
method: 'POST',
|
||
body: data,
|
||
credentials: 'same-origin',
|
||
}).then(function (response) {
|
||
return response.json();
|
||
}).then(function (payload) {
|
||
if (!payload.success) {
|
||
throw new Error((payload.data && payload.data.message) || '提交失败');
|
||
}
|
||
|
||
if (payload.data && payload.data.redirect) {
|
||
window.location.href = payload.data.redirect;
|
||
return;
|
||
}
|
||
|
||
setFeedback(feedback, (payload.data && payload.data.message) || '主题已提交。', 'is-success');
|
||
}).catch(function (error) {
|
||
setFeedback(feedback, error.message || '提交失败,请稍后重试。', 'is-error');
|
||
submitButton.disabled = false;
|
||
});
|
||
});
|
||
}
|
||
|
||
function bindModeratorApplyForm(form) {
|
||
var feedback = form.querySelector('.js-aksrt-action-feedback');
|
||
var submitButton = form.querySelector('button[type="submit"]');
|
||
|
||
form.addEventListener('submit', function (event) {
|
||
event.preventDefault();
|
||
|
||
var boardId = parseInt(form.getAttribute('data-board-id') || '0', 10);
|
||
var reasonField = form.querySelector('[name="reason"]');
|
||
var reason = reasonField ? reasonField.value.trim() : '';
|
||
|
||
if (!boardId || !reason) {
|
||
setFeedback(feedback, '请填写完整的申请理由。', 'is-error');
|
||
return;
|
||
}
|
||
|
||
if (submitButton) {
|
||
submitButton.disabled = true;
|
||
}
|
||
setFeedback(feedback, '正在提交申请…', 'is-loading');
|
||
|
||
request('/forum/moderator/apply', {
|
||
method: 'POST',
|
||
body: JSON.stringify({
|
||
board_id: boardId,
|
||
reason: reason,
|
||
}),
|
||
}).then(function (payload) {
|
||
setFeedback(feedback, payload.message || '申请已提交', 'is-success');
|
||
if (submitButton) submitButton.disabled = true;
|
||
// Disable the form to prevent re-submission
|
||
var reasonField = form.querySelector('[name="reason"]');
|
||
if (reasonField) reasonField.disabled = true;
|
||
}).catch(function (error) {
|
||
setFeedback(feedback, error.message || '申请提交失败。', 'is-error');
|
||
if (submitButton) {
|
||
submitButton.disabled = false;
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
function bindVoteForm(form) {
|
||
var feedback = form.querySelector('.js-aksrt-action-feedback');
|
||
var submitButton = form.querySelector('button[type="submit"]');
|
||
|
||
form.addEventListener('submit', function (event) {
|
||
event.preventDefault();
|
||
|
||
var topicId = parseInt(form.getAttribute('data-topic-id') || '0', 10);
|
||
var checked = Array.prototype.slice.call(form.querySelectorAll('input[name="option_ids[]"]:checked')).map(function (input) {
|
||
return input.value;
|
||
});
|
||
|
||
if (!topicId || checked.length === 0) {
|
||
setFeedback(feedback, '请选择至少一个投票选项。', 'is-error');
|
||
return;
|
||
}
|
||
|
||
if (submitButton) {
|
||
submitButton.disabled = true;
|
||
}
|
||
setFeedback(feedback, '正在提交投票…', 'is-loading');
|
||
|
||
request('/forum/topics/' + topicId + '/vote', {
|
||
method: 'POST',
|
||
body: JSON.stringify({ option_ids: checked }),
|
||
}).then(function (payload) {
|
||
setFeedback(feedback, payload.message || '投票成功', 'is-success');
|
||
// Disable all checkboxes and submit after vote
|
||
var checkboxes = form.querySelectorAll('input[type="checkbox"]');
|
||
for (var i = 0; i < checkboxes.length; i++) checkboxes[i].disabled = true;
|
||
if (submitButton) submitButton.disabled = true;
|
||
}).catch(function (error) {
|
||
setFeedback(feedback, error.message || '投票失败。', 'is-error');
|
||
if (submitButton) {
|
||
submitButton.disabled = false;
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
function buildModerationPayload(form, action) {
|
||
var noteField = form.querySelector('[name="note"]');
|
||
var payload = {
|
||
action: action,
|
||
note: noteField ? noteField.value.trim() : '',
|
||
};
|
||
|
||
if (action === 'review') {
|
||
payload.review_status = (form.querySelector('[name="review_status"]') || {}).value || '';
|
||
} else if (action === 'move_board') {
|
||
payload.target_board_id = parseInt((form.querySelector('[name="target_board_id"]') || {}).value || '0', 10);
|
||
} else if (action === 'visibility') {
|
||
payload.visibility = (form.querySelector('[name="visibility"]') || {}).value || '';
|
||
if (payload.visibility === 'credits') {
|
||
payload.credits_cost = parseInt((form.querySelector('[name="credits_cost"]') || {}).value || '0', 10);
|
||
} else if (payload.visibility === 'pay') {
|
||
payload.pay_price = (form.querySelector('[name="pay_price"]') || {}).value || '';
|
||
} else if (payload.visibility === 'role') {
|
||
payload.visibility_roles = Array.prototype.slice.call(form.querySelectorAll('[name="visibility_roles[]"] option:checked')).map(function (option) {
|
||
return option.value;
|
||
});
|
||
}
|
||
} else if (action === 'sticky') {
|
||
// 置顶分级(§7.3):发送 0~3 整数,而非布尔值。
|
||
payload.value = parseInt((form.querySelector('[name="sticky_value"]') || {}).value || '0', 10);
|
||
} else if (action === 'question_status') {
|
||
payload.value = parseInt((form.querySelector('[name="question_status_value"]') || {}).value || '0', 10);
|
||
} else if (action === 'delete' || action === 'undelete') {
|
||
payload.value = true;
|
||
} else {
|
||
var valueFieldName = action + '_value';
|
||
payload.value = ((form.querySelector('[name="' + valueFieldName + '"]') || {}).value || '0') === '1';
|
||
}
|
||
|
||
return payload;
|
||
}
|
||
|
||
function bindModerationFieldToggle(form) {
|
||
var actionField = form.querySelector('.js-aksrt-moderation-action');
|
||
var groups = form.querySelectorAll('.js-aksrt-moderation-field');
|
||
var visibilitySelect = form.querySelector('[name="visibility"]');
|
||
var visibilityExtras = form.querySelectorAll('.js-aksrt-visibility-extra');
|
||
if (!actionField || !groups.length) {
|
||
return;
|
||
}
|
||
|
||
function syncVisibilityExtras() {
|
||
if (!visibilitySelect || !visibilityExtras.length) {
|
||
return;
|
||
}
|
||
var visibility = visibilitySelect.value;
|
||
visibilityExtras.forEach(function (group) {
|
||
group.hidden = actionField.value !== 'visibility' || group.getAttribute('data-visibility-field') !== visibility;
|
||
});
|
||
}
|
||
|
||
function sync() {
|
||
var action = actionField.value;
|
||
groups.forEach(function (group) {
|
||
var fieldName = group.getAttribute('data-field');
|
||
if (group.classList.contains('js-aksrt-visibility-extra')) {
|
||
return;
|
||
}
|
||
group.hidden = fieldName !== action;
|
||
});
|
||
syncVisibilityExtras();
|
||
}
|
||
|
||
actionField.addEventListener('change', sync);
|
||
if (visibilitySelect) {
|
||
visibilitySelect.addEventListener('change', syncVisibilityExtras);
|
||
}
|
||
sync();
|
||
}
|
||
|
||
function bindModerationForm(form) {
|
||
var feedback = form.querySelector('.js-aksrt-action-feedback');
|
||
var submitButton = form.querySelector('button[type="submit"]');
|
||
bindModerationFieldToggle(form);
|
||
|
||
form.addEventListener('submit', function (event) {
|
||
event.preventDefault();
|
||
|
||
var topicId = parseInt(form.getAttribute('data-topic-id') || '0', 10);
|
||
var actionField = form.querySelector('.js-aksrt-moderation-action');
|
||
var action = actionField ? actionField.value : '';
|
||
if (!topicId || !action) {
|
||
setFeedback(feedback, '请选择治理动作。', 'is-error');
|
||
return;
|
||
}
|
||
|
||
if (submitButton) {
|
||
submitButton.disabled = true;
|
||
}
|
||
if (action === 'delete' && !window.confirm('确认将该主题移入回收站吗?')) {
|
||
if (submitButton) submitButton.disabled = false;
|
||
return;
|
||
}
|
||
if (action === 'undelete' && !window.confirm('确认恢复该主题吗?')) {
|
||
if (submitButton) submitButton.disabled = false;
|
||
return;
|
||
}
|
||
setFeedback(feedback, '正在执行治理动作…', 'is-loading');
|
||
|
||
request('/forum/topics/' + topicId + '/moderate', {
|
||
method: 'POST',
|
||
body: JSON.stringify(buildModerationPayload(form, action)),
|
||
}).then(function (payload) {
|
||
setFeedback(feedback, payload.message || '治理动作已执行', 'is-success');
|
||
if (submitButton) submitButton.disabled = true;
|
||
}).catch(function (error) {
|
||
setFeedback(feedback, error.message || '治理动作执行失败。', 'is-error');
|
||
if (submitButton) {
|
||
submitButton.disabled = false;
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
function bindQuickTopicAction(button) {
|
||
button.addEventListener('click', function () {
|
||
var topicId = parseInt(button.getAttribute('data-topic-id') || '0', 10);
|
||
var action = button.getAttribute('data-action') || '';
|
||
var rawValue = button.getAttribute('data-value') || '0';
|
||
var valueType = button.getAttribute('data-value-type') || 'bool';
|
||
// 置顶分级(§7.3):data-value-type="int" 时发送整数级别,否则发送布尔值。
|
||
var value = valueType === 'int' ? parseInt(rawValue, 10) : rawValue === '1';
|
||
|
||
if (!topicId || !action) {
|
||
return;
|
||
}
|
||
|
||
button.disabled = true;
|
||
request('/forum/topics/' + topicId + '/moderate', {
|
||
method: 'POST',
|
||
body: JSON.stringify({
|
||
action: action,
|
||
value: value,
|
||
}),
|
||
}).then(function () {
|
||
// Toggle button visual state instead of reloading
|
||
var icon = button.querySelector('i');
|
||
if (valueType === 'int' ? value > 0 : value) {
|
||
button.classList.add('is-active');
|
||
if (icon) icon.className = icon.className.replace('far', 'fas');
|
||
} else {
|
||
button.classList.remove('is-active');
|
||
if (icon) icon.className = icon.className.replace('fas', 'far');
|
||
}
|
||
button.disabled = false;
|
||
}).catch(function (error) {
|
||
var msg = error.message || '治理动作执行失败。';
|
||
if (typeof window.aksrtToast === 'function') { window.aksrtToast(msg, 'error'); }
|
||
else { window.alert(msg); }
|
||
button.disabled = false;
|
||
});
|
||
});
|
||
}
|
||
|
||
function bindFavoriteButton(button) {
|
||
button.addEventListener('click', function () {
|
||
var topicId = button.getAttribute('data-topic-id');
|
||
if (!topicId || button.disabled) {
|
||
return;
|
||
}
|
||
|
||
button.disabled = true;
|
||
request('/forum/topics/' + topicId + '/favorite', {
|
||
method: 'POST',
|
||
body: JSON.stringify({}),
|
||
}).then(function (payload) {
|
||
var isFav = !!(payload.favorited);
|
||
var icon = button.querySelector('i');
|
||
var label = button.querySelector('.js-aksrt-favorite-label');
|
||
button.setAttribute('data-favorited', isFav ? '1' : '0');
|
||
if (icon) {
|
||
icon.className = isFav ? 'fas fa-bookmark' : 'far fa-bookmark';
|
||
}
|
||
if (label) {
|
||
label.textContent = isFav ? '已收藏' : '收藏';
|
||
}
|
||
button.disabled = false;
|
||
}).catch(function (error) {
|
||
var msg = error.message || '操作失败';
|
||
if (typeof window.aksrtToast === 'function') { window.aksrtToast(msg, 'error'); }
|
||
else { window.alert(msg); }
|
||
button.disabled = false;
|
||
});
|
||
});
|
||
}
|
||
|
||
function bindScoreButton(button) {
|
||
button.addEventListener('click', function () {
|
||
var container = button.closest('.aksrt-forum-topic__score-actions');
|
||
if (!container || button.disabled) {
|
||
return;
|
||
}
|
||
|
||
var topicId = container.getAttribute('data-topic-id');
|
||
var amount = parseInt(button.getAttribute('data-amount') || '0', 10);
|
||
var feedback = container.querySelector('.js-aksrt-action-feedback');
|
||
|
||
if (!topicId || amount === 0) {
|
||
return;
|
||
}
|
||
|
||
button.disabled = true;
|
||
setFeedback(feedback, '提交中…', 'is-loading');
|
||
|
||
request('/forum/topics/' + topicId + '/score', {
|
||
method: 'POST',
|
||
body: JSON.stringify({ amount: amount }),
|
||
}).then(function (payload) {
|
||
var scoreEl = container.querySelector('.js-aksrt-score-value');
|
||
if (scoreEl && payload.score !== undefined) {
|
||
scoreEl.textContent = String(payload.score);
|
||
}
|
||
setFeedback(feedback, payload.message || '评分成功', 'is-success');
|
||
// Disable both score buttons after success (one-time per user)
|
||
container.querySelectorAll('.js-aksrt-topic-score').forEach(function (btn) {
|
||
btn.disabled = true;
|
||
});
|
||
}).catch(function (error) {
|
||
setFeedback(feedback, error.message || '评分失败', 'is-error');
|
||
button.disabled = false;
|
||
});
|
||
});
|
||
}
|
||
|
||
function bindAdoptButton(button) {
|
||
button.addEventListener('click', function () {
|
||
var topicId = button.getAttribute('data-topic-id');
|
||
var commentId = button.getAttribute('data-comment-id');
|
||
if (!topicId || !commentId || button.disabled) {
|
||
return;
|
||
}
|
||
|
||
if (!window.confirm('确认采纳该回复为最佳答案?')) {
|
||
return;
|
||
}
|
||
|
||
button.disabled = true;
|
||
request('/forum/topics/' + topicId + '/adopt', {
|
||
method: 'POST',
|
||
body: JSON.stringify({ comment_id: parseInt(commentId, 10) }),
|
||
}).then(function (payload) {
|
||
button.textContent = '✓ 已采纳';
|
||
button.classList.add('is-adopted');
|
||
// Disable all other adopt buttons
|
||
document.querySelectorAll('.js-aksrt-adopt-answer').forEach(function (btn) {
|
||
btn.disabled = true;
|
||
});
|
||
}).catch(function (error) {
|
||
var msg = error.message || '采纳失败';
|
||
if (typeof window.aksrtToast === 'function') { window.aksrtToast(msg, 'error'); }
|
||
else { window.alert(msg); }
|
||
button.disabled = false;
|
||
});
|
||
});
|
||
}
|
||
|
||
function bindReportModal(modal) {
|
||
var form = modal.querySelector('.js-aksrt-report-form');
|
||
var feedback = modal.querySelector('.js-aksrt-action-feedback');
|
||
var targetLabel = modal.querySelector('.js-aksrt-report-target');
|
||
var targetTypeField = form ? form.querySelector('[name="target_type"]') : null;
|
||
var targetIdField = form ? form.querySelector('[name="target_id"]') : null;
|
||
var closeButtons = modal.querySelectorAll('.js-aksrt-report-close');
|
||
|
||
function openModal(trigger) {
|
||
if (!form) return;
|
||
var targetType = trigger.getAttribute('data-target-type') || 'post';
|
||
var targetId = trigger.getAttribute('data-target-id') || '';
|
||
var targetTitle = trigger.getAttribute('data-target-title') || '';
|
||
if (targetTypeField) targetTypeField.value = targetType;
|
||
if (targetIdField) targetIdField.value = targetId;
|
||
if (targetLabel) {
|
||
targetLabel.textContent = '举报对象:' + (targetTitle || ('#' + targetId));
|
||
}
|
||
modal.hidden = false;
|
||
document.body.classList.add('is-report-modal-open');
|
||
}
|
||
|
||
function closeModal() {
|
||
modal.hidden = true;
|
||
document.body.classList.remove('is-report-modal-open');
|
||
if (form) form.reset();
|
||
setFeedback(feedback, '', '');
|
||
}
|
||
|
||
document.querySelectorAll('.js-aksrt-report-trigger').forEach(function (trigger) {
|
||
trigger.addEventListener('click', function () {
|
||
openModal(trigger);
|
||
});
|
||
});
|
||
|
||
closeButtons.forEach(function (btn) {
|
||
btn.addEventListener('click', closeModal);
|
||
});
|
||
|
||
if (!form) return;
|
||
|
||
form.addEventListener('submit', function (event) {
|
||
event.preventDefault();
|
||
var reason = (form.querySelector('[name="reason"]') || {}).value || '';
|
||
if (!reason.trim()) {
|
||
setFeedback(feedback, '请填写举报说明。', 'is-error');
|
||
return;
|
||
}
|
||
setFeedback(feedback, '正在提交举报…', 'is-loading');
|
||
request('/report/submit', {
|
||
method: 'POST',
|
||
body: JSON.stringify({
|
||
target_type: targetTypeField ? targetTypeField.value : 'post',
|
||
target_id: parseInt(targetIdField ? targetIdField.value : '0', 10),
|
||
category: (form.querySelector('[name="category"]') || {}).value || 'other',
|
||
reason: reason,
|
||
}),
|
||
}).then(function (payload) {
|
||
setFeedback(feedback, payload.message || '举报已提交', 'is-success');
|
||
setTimeout(closeModal, 900);
|
||
}).catch(function (error) {
|
||
setFeedback(feedback, error.message || '举报提交失败。', 'is-error');
|
||
});
|
||
});
|
||
}
|
||
|
||
function bindComposeVisibilityToggle(form) {
|
||
var visSelect = form.querySelector('#compose-visibility');
|
||
var creditsField = form.querySelector('#compose-credits-cost-field');
|
||
var payField = form.querySelector('#compose-pay-price-field');
|
||
var roleField = form.querySelector('#compose-role-field');
|
||
|
||
if (!visSelect) return;
|
||
|
||
function syncVisFields() {
|
||
var val = visSelect.value;
|
||
if (creditsField) creditsField.style.display = val === 'credits' ? '' : 'none';
|
||
if (payField) payField.style.display = val === 'pay' ? '' : 'none';
|
||
if (roleField) roleField.style.display = val === 'role' ? '' : 'none';
|
||
}
|
||
|
||
visSelect.addEventListener('change', syncVisFields);
|
||
syncVisFields();
|
||
}
|
||
|
||
function bindUnlockButton(button) {
|
||
button.addEventListener('click', function () {
|
||
var topicId = parseInt(button.getAttribute('data-topic-id') || '0', 10);
|
||
var cost = button.getAttribute('data-cost') || '0';
|
||
var feedback = button.parentElement ? button.parentElement.querySelector('.js-aksrt-action-feedback') : null;
|
||
|
||
if (!topicId || !window.confirm('确认使用 ' + cost + ' 积分解锁此主题?')) {
|
||
return;
|
||
}
|
||
|
||
button.disabled = true;
|
||
setFeedback(feedback, '正在解锁…', 'is-loading');
|
||
|
||
var data = new FormData();
|
||
data.append('action', 'aksrt_forum_unlock_topic');
|
||
data.append('topic_id', topicId);
|
||
data.append('_nonce', rootData.forumNonce || '');
|
||
|
||
fetch((rootData.ajaxUrl || '/wp-admin/admin-ajax.php'), {
|
||
method: 'POST',
|
||
body: data,
|
||
credentials: 'same-origin',
|
||
}).then(function (r) { return r.json(); }).then(function (payload) {
|
||
if (!payload.success) {
|
||
throw new Error((payload.data && payload.data.message) || '解锁失败');
|
||
}
|
||
setFeedback(feedback, '解锁成功,正在刷新…', 'is-success');
|
||
setTimeout(function () { window.location.reload(); }, 800);
|
||
}).catch(function (error) {
|
||
setFeedback(feedback, error.message || '解锁失败', 'is-error');
|
||
button.disabled = false;
|
||
});
|
||
});
|
||
}
|
||
|
||
function formatFollowPayLabel(pay) {
|
||
pay = pay || {};
|
||
if (pay.is_free) {
|
||
return 'VIP 免费关注';
|
||
}
|
||
if (pay.label) {
|
||
return String(pay.label);
|
||
}
|
||
if (pay.modo === 'points') {
|
||
return String(pay.amount || 0) + ' 积分';
|
||
}
|
||
return '¥' + String(pay.amount || '0');
|
||
}
|
||
|
||
function purchasePlateFollow(plateId, button, payHint) {
|
||
payHint = payHint || {};
|
||
var modo = String(payHint.modo || 'money');
|
||
|
||
// Cash (paid or VIP free): multi-gateway cashier — free VIP still creates 0-order for ledger.
|
||
// No Credits×100 bypass.
|
||
if (modo === 'money') {
|
||
button.disabled = false;
|
||
if (typeof window.aksrtOpenCashier === 'function') {
|
||
window.aksrtOpenCashier(plateId, button, '', '', 'plate_follow');
|
||
return;
|
||
}
|
||
var msgCashier = '收银台未加载,请刷新页面后重试';
|
||
if (typeof window.aksrtToast === 'function') { window.aksrtToast(msgCashier, 'error'); }
|
||
else { window.alert(msgCashier); }
|
||
return;
|
||
}
|
||
|
||
// Points / points VIP free: keep AJAX purchase path.
|
||
var confirmMsg = '确认付费关注该版块?';
|
||
if (payHint.is_free) {
|
||
confirmMsg = '确认使用 VIP 免费关注该版块?';
|
||
} else {
|
||
confirmMsg = '确认支付 ' + formatFollowPayLabel(payHint) + ' 关注该版块?';
|
||
}
|
||
if (!window.confirm(confirmMsg)) {
|
||
button.disabled = false;
|
||
return;
|
||
}
|
||
|
||
var data = new FormData();
|
||
data.append('action', 'aksrt_forum_purchase_plate_follow');
|
||
data.append('plate_id', plateId);
|
||
data.append('_nonce', rootData.forumNonce || '');
|
||
|
||
fetch((rootData.ajaxUrl || '/wp-admin/admin-ajax.php'), {
|
||
method: 'POST',
|
||
body: data,
|
||
credentials: 'same-origin',
|
||
}).then(function (r) { return r.json(); }).then(function (payload) {
|
||
if (!payload.success) {
|
||
var errData = payload.data || {};
|
||
// Server may redirect money path to cashier.
|
||
if (errData.require_cashier && typeof window.aksrtOpenCashier === 'function') {
|
||
button.disabled = false;
|
||
window.aksrtOpenCashier(plateId, button, '', '', 'plate_follow');
|
||
return;
|
||
}
|
||
throw new Error(errData.message || '支付失败');
|
||
}
|
||
var res = payload.data || {};
|
||
button.setAttribute('data-followed', '1');
|
||
button.classList.add('is-followed');
|
||
if (button.querySelector('i') && button.childNodes.length) {
|
||
button.innerHTML = '<i class="fas fa-heart"></i> 已关注';
|
||
} else {
|
||
button.textContent = '已关注';
|
||
}
|
||
if (typeof window.aksrtToast === 'function') {
|
||
window.aksrtToast(res.message || '关注成功', 'success');
|
||
}
|
||
setTimeout(function () { window.location.reload(); }, 600);
|
||
}).catch(function (error) {
|
||
var msg = error.message || '支付失败';
|
||
if (typeof window.aksrtToast === 'function') { window.aksrtToast(msg, 'error'); }
|
||
else { window.alert(msg); }
|
||
button.disabled = false;
|
||
});
|
||
}
|
||
|
||
function bindFollowPlateButton(button) {
|
||
button.addEventListener('click', function () {
|
||
var plateId = parseInt(button.getAttribute('data-plate-id') || '0', 10);
|
||
if (!plateId || button.disabled) {
|
||
return;
|
||
}
|
||
button.disabled = true;
|
||
|
||
var data = new FormData();
|
||
data.append('action', 'aksrt_forum_follow_plate');
|
||
data.append('plate_id', plateId);
|
||
data.append('_nonce', rootData.forumNonce || '');
|
||
|
||
fetch((rootData.ajaxUrl || '/wp-admin/admin-ajax.php'), {
|
||
method: 'POST',
|
||
body: data,
|
||
credentials: 'same-origin',
|
||
}).then(function (r) { return r.json(); }).then(function (payload) {
|
||
// Paid follow required
|
||
if (!payload.success && payload.data && payload.data.require_pay) {
|
||
purchasePlateFollow(plateId, button, payload.data.pay || {});
|
||
return;
|
||
}
|
||
if (!payload.success) {
|
||
throw new Error((payload.data && payload.data.message) || '操作失败');
|
||
}
|
||
var res = payload.data || {};
|
||
var followed = !!res.followed;
|
||
button.setAttribute('data-followed', followed ? '1' : '0');
|
||
button.classList.toggle('is-followed', followed);
|
||
button.innerHTML = followed
|
||
? '<i class="fas fa-heart"></i> 已关注'
|
||
: '<i class="fas fa-heart"></i> 关注';
|
||
button.disabled = false;
|
||
}).catch(function (error) {
|
||
var msg = error.message || '操作失败';
|
||
if (typeof window.aksrtToast === 'function') { window.aksrtToast(msg, 'error'); }
|
||
else { window.alert(msg); }
|
||
button.disabled = false;
|
||
});
|
||
});
|
||
}
|
||
|
||
function bindComposeCoverToggle(form) {
|
||
var coverTypeSelect = form.querySelector('#compose-cover-type');
|
||
var imageField = form.querySelector('#compose-cover-image-field');
|
||
var slideField = form.querySelector('#compose-cover-slide-field');
|
||
var videoField = form.querySelector('#compose-cover-video-field');
|
||
|
||
if (!coverTypeSelect) return;
|
||
|
||
function syncCoverFields() {
|
||
var val = coverTypeSelect.value;
|
||
if (imageField) imageField.style.display = val === 'image' ? '' : 'none';
|
||
if (slideField) slideField.style.display = val === 'slide' ? '' : 'none';
|
||
if (videoField) videoField.style.display = val === 'video' ? '' : 'none';
|
||
}
|
||
|
||
coverTypeSelect.addEventListener('change', syncCoverFields);
|
||
syncCoverFields();
|
||
|
||
var imageInput = form.querySelector('#compose-cover-image');
|
||
var imagePreview = form.querySelector('#compose-cover-preview');
|
||
var imageBtn = form.querySelector('#compose-cover-upload-btn');
|
||
|
||
if (imageBtn && typeof wp !== 'undefined' && wp.media) {
|
||
imageBtn.addEventListener('click', function () {
|
||
var frame = wp.media({ title: '选择封面图片', multiple: false, library: { type: 'image' } });
|
||
frame.on('select', function () {
|
||
var attachment = frame.state().get('selection').first().toJSON();
|
||
if (imageInput) imageInput.value = attachment.url;
|
||
if (imagePreview) imagePreview.innerHTML = '<img src="' + attachment.url + '" alt="">';
|
||
});
|
||
frame.open();
|
||
});
|
||
}
|
||
|
||
var slideInput = form.querySelector('#compose-featured-slide');
|
||
var slidePreview = form.querySelector('#compose-slide-preview');
|
||
var slideBtn = form.querySelector('#compose-slide-upload-btn');
|
||
|
||
if (slideBtn && typeof wp !== 'undefined' && wp.media) {
|
||
slideBtn.addEventListener('click', function () {
|
||
var frame = wp.media({ title: '选择幻灯片图片', multiple: true, library: { type: 'image' } });
|
||
frame.on('select', function () {
|
||
var urls = frame.state().get('selection').map(function (a) { return a.toJSON().url; });
|
||
urls = urls.slice(0, 9);
|
||
if (slideInput) slideInput.value = JSON.stringify(urls);
|
||
if (slidePreview) {
|
||
slidePreview.innerHTML = urls.map(function (u) { return '<img src="' + u + '" alt="">'; }).join('');
|
||
}
|
||
});
|
||
frame.open();
|
||
});
|
||
}
|
||
}
|
||
|
||
function bindEditPlateButton(button) {
|
||
button.addEventListener('click', function () {
|
||
var plateId = button.getAttribute('data-plate-id');
|
||
var name = window.prompt('版块名称:', button.getAttribute('data-name') || '');
|
||
if (name === null) return;
|
||
var description = window.prompt('版块描述:', button.getAttribute('data-description') || '');
|
||
if (description === null) description = '';
|
||
|
||
request('/forum/front/plates/' + plateId, {
|
||
method: 'POST',
|
||
body: JSON.stringify({ name: name, description: description }),
|
||
}).then(function () {
|
||
window.location.reload();
|
||
}).catch(function (error) {
|
||
window.alert(error.message || '编辑失败');
|
||
});
|
||
});
|
||
}
|
||
|
||
function bindDeletePlateButton(button) {
|
||
button.addEventListener('click', function () {
|
||
var plateId = button.getAttribute('data-plate-id');
|
||
var topicCount = parseInt(button.getAttribute('data-topic-count') || '0', 10);
|
||
var msg = '确认删除此版块?';
|
||
if (topicCount > 0) {
|
||
msg += '\n该版块下有 ' + topicCount + ' 个主题,删除后将移入回收站。';
|
||
}
|
||
if (!window.confirm(msg)) return;
|
||
|
||
request('/forum/front/plates/' + plateId, {
|
||
method: 'DELETE',
|
||
body: JSON.stringify({ cascade: 'trash' }),
|
||
}).then(function () {
|
||
window.location.href = (rootData.siteUrl || '') + '/forums/';
|
||
}).catch(function (error) {
|
||
window.alert(error.message || '删除失败');
|
||
});
|
||
});
|
||
}
|
||
|
||
// ──────────────────────────────────────────────────────────
|
||
// §7.4 — Remote search selector
|
||
// ──────────────────────────────────────────────────────────
|
||
|
||
function bindRemoteSelects(container) {
|
||
var selects = container.querySelectorAll('.aksrt-remote-select');
|
||
selects.forEach(function (wrapper) {
|
||
var searchAction = wrapper.getAttribute('data-search-action');
|
||
var hiddenInput = wrapper.querySelector('input[type="hidden"]');
|
||
var textInput = wrapper.querySelector('.js-aksrt-remote-input');
|
||
var dropdown = wrapper.querySelector('.aksrt-remote-select__dropdown');
|
||
if (!searchAction || !hiddenInput || !textInput || !dropdown) return;
|
||
|
||
var debounceTimer = null;
|
||
var ajaxUrl = (rootData.ajaxUrl || '/wp-admin/admin-ajax.php');
|
||
|
||
textInput.addEventListener('input', function () {
|
||
clearTimeout(debounceTimer);
|
||
var q = textInput.value.trim();
|
||
debounceTimer = setTimeout(function () {
|
||
fetch(ajaxUrl + '?action=' + encodeURIComponent(searchAction) + '&q=' + encodeURIComponent(q), {
|
||
credentials: 'same-origin',
|
||
}).then(function (r) { return r.json(); }).then(function (payload) {
|
||
if (!payload.success || !payload.data) return;
|
||
dropdown.innerHTML = '';
|
||
payload.data.forEach(function (item) {
|
||
var div = document.createElement('div');
|
||
div.className = 'aksrt-remote-select__option';
|
||
div.textContent = item.name;
|
||
div.setAttribute('data-id', String(item.id));
|
||
div.addEventListener('mousedown', function (e) {
|
||
e.preventDefault();
|
||
hiddenInput.value = item.id;
|
||
textInput.value = item.name;
|
||
dropdown.hidden = true;
|
||
});
|
||
dropdown.appendChild(div);
|
||
});
|
||
dropdown.hidden = payload.data.length === 0;
|
||
});
|
||
}, 250);
|
||
});
|
||
|
||
textInput.addEventListener('focus', function () {
|
||
if (dropdown.children.length > 0) dropdown.hidden = false;
|
||
textInput.dispatchEvent(new Event('input'));
|
||
});
|
||
textInput.addEventListener('blur', function () {
|
||
setTimeout(function () { dropdown.hidden = true; }, 200);
|
||
});
|
||
});
|
||
}
|
||
|
||
// ──────────────────────────────────────────────────────────
|
||
// §7.4 — Tag tokenizer
|
||
// ──────────────────────────────────────────────────────────
|
||
|
||
function bindTagInputs(container) {
|
||
var wrappers = container.querySelectorAll('.aksrt-tag-input');
|
||
wrappers.forEach(function (wrapper) {
|
||
var searchAction = wrapper.getAttribute('data-search-action');
|
||
var maxTags = parseInt(wrapper.getAttribute('data-max') || '5', 10);
|
||
var hiddenInput = wrapper.querySelector('input[type="hidden"]');
|
||
var tokenContainer = wrapper.querySelector('.aksrt-tag-input__tokens');
|
||
var textInput = wrapper.querySelector('.js-aksrt-tag-search');
|
||
var dropdown = wrapper.querySelector('.aksrt-tag-input__dropdown');
|
||
if (!hiddenInput || !tokenContainer || !textInput) return;
|
||
|
||
var tags = [];
|
||
var initialVal = (hiddenInput.value || '').trim();
|
||
if (initialVal) {
|
||
initialVal.split(/[,,]/).forEach(function (t) {
|
||
t = t.trim();
|
||
if (t && tags.indexOf(t) === -1) tags.push(t);
|
||
});
|
||
}
|
||
|
||
function syncHidden() {
|
||
hiddenInput.value = tags.join(', ');
|
||
}
|
||
|
||
function renderTokens() {
|
||
tokenContainer.innerHTML = '';
|
||
tags.forEach(function (tag, idx) {
|
||
var span = document.createElement('span');
|
||
span.className = 'aksrt-tag-input__token';
|
||
span.textContent = tag;
|
||
var close = document.createElement('button');
|
||
close.type = 'button';
|
||
close.className = 'aksrt-tag-input__token-remove';
|
||
close.innerHTML = '×';
|
||
close.addEventListener('click', function () {
|
||
tags.splice(idx, 1);
|
||
syncHidden();
|
||
renderTokens();
|
||
});
|
||
span.appendChild(close);
|
||
tokenContainer.appendChild(span);
|
||
});
|
||
}
|
||
|
||
function addTag(name) {
|
||
name = name.trim();
|
||
if (!name || tags.indexOf(name) !== -1 || tags.length >= maxTags) return;
|
||
tags.push(name);
|
||
syncHidden();
|
||
renderTokens();
|
||
textInput.value = '';
|
||
}
|
||
|
||
renderTokens();
|
||
|
||
textInput.addEventListener('keydown', function (e) {
|
||
if (e.key === 'Enter' || e.key === ',') {
|
||
e.preventDefault();
|
||
addTag(textInput.value);
|
||
if (dropdown) dropdown.hidden = true;
|
||
}
|
||
if (e.key === 'Backspace' && textInput.value === '' && tags.length > 0) {
|
||
tags.pop();
|
||
syncHidden();
|
||
renderTokens();
|
||
}
|
||
});
|
||
|
||
if (searchAction && dropdown) {
|
||
var ajaxUrl = (rootData.ajaxUrl || '/wp-admin/admin-ajax.php');
|
||
var debounce = null;
|
||
|
||
textInput.addEventListener('input', function () {
|
||
clearTimeout(debounce);
|
||
var q = textInput.value.trim();
|
||
if (!q) { dropdown.hidden = true; return; }
|
||
debounce = setTimeout(function () {
|
||
fetch(ajaxUrl + '?action=' + encodeURIComponent(searchAction) + '&q=' + encodeURIComponent(q), {
|
||
credentials: 'same-origin',
|
||
}).then(function (r) { return r.json(); }).then(function (payload) {
|
||
if (!payload.success || !payload.data) return;
|
||
dropdown.innerHTML = '';
|
||
payload.data.forEach(function (item) {
|
||
var div = document.createElement('div');
|
||
div.className = 'aksrt-tag-input__suggestion';
|
||
div.textContent = item.name + (item.count !== undefined ? ' (' + item.count + ')' : '');
|
||
div.addEventListener('mousedown', function (e) {
|
||
e.preventDefault();
|
||
addTag(item.name);
|
||
dropdown.hidden = true;
|
||
});
|
||
dropdown.appendChild(div);
|
||
});
|
||
dropdown.hidden = payload.data.length === 0;
|
||
});
|
||
}, 250);
|
||
});
|
||
|
||
textInput.addEventListener('blur', function () {
|
||
setTimeout(function () { dropdown.hidden = true; }, 200);
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
// ──────────────────────────────────────────────────────────
|
||
// §7.4 — Title character counter
|
||
// ──────────────────────────────────────────────────────────
|
||
|
||
function bindTitleCounter(form) {
|
||
var titleInput = form.querySelector('#compose-title');
|
||
var counterCurrent = form.querySelector('.js-aksrt-counter-current');
|
||
if (!titleInput || !counterCurrent) return;
|
||
|
||
function update() {
|
||
counterCurrent.textContent = String(titleInput.value.length);
|
||
var max = parseInt(titleInput.getAttribute('data-aksrt-maxlength') || '30', 10);
|
||
var parent = counterCurrent.closest('.aksrt-forum-compose__char-counter');
|
||
if (parent) {
|
||
parent.classList.toggle('is-over', titleInput.value.length > max);
|
||
parent.classList.toggle('is-near', titleInput.value.length > max * 0.8 && titleInput.value.length <= max);
|
||
}
|
||
}
|
||
|
||
titleInput.addEventListener('input', update);
|
||
update();
|
||
}
|
||
|
||
// ──────────────────────────────────────────────────────────
|
||
// §7.4 — Draft list toggle & delete
|
||
// ──────────────────────────────────────────────────────────
|
||
|
||
function bindDraftUI() {
|
||
var toggle = document.querySelector('.js-aksrt-draft-toggle');
|
||
var list = document.querySelector('#compose-draft-list');
|
||
if (toggle && list) {
|
||
toggle.addEventListener('click', function () {
|
||
list.hidden = !list.hidden;
|
||
var icon = toggle.querySelector('i.fa-chevron-down, i.fa-chevron-up');
|
||
if (icon) {
|
||
icon.classList.toggle('fa-chevron-down');
|
||
icon.classList.toggle('fa-chevron-up');
|
||
}
|
||
});
|
||
}
|
||
|
||
document.querySelectorAll('.js-aksrt-delete-draft').forEach(function (btn) {
|
||
btn.addEventListener('click', function () {
|
||
var draftId = btn.getAttribute('data-draft-id');
|
||
if (!draftId || !window.confirm('确认删除此草稿?')) return;
|
||
|
||
var ajaxUrl = (rootData.ajaxUrl || '/wp-admin/admin-ajax.php');
|
||
var nonce = '';
|
||
var form = document.querySelector('.js-aksrt-forum-compose-form');
|
||
if (form) nonce = form.getAttribute('data-nonce') || '';
|
||
|
||
var data = new FormData();
|
||
data.append('action', 'aksrt_forum_delete_draft');
|
||
data.append('_nonce', nonce);
|
||
data.append('draft_id', draftId);
|
||
|
||
fetch(ajaxUrl, { method: 'POST', body: data, credentials: 'same-origin' })
|
||
.then(function (r) { return r.json(); })
|
||
.then(function (payload) {
|
||
if (payload.success) {
|
||
var item = btn.closest('.aksrt-forum-compose__draft-item');
|
||
if (item) item.remove();
|
||
}
|
||
});
|
||
});
|
||
});
|
||
}
|
||
|
||
// ──────────────────────────────────────────────────────────
|
||
// §7.4 — Edit form AJAX submit
|
||
// ──────────────────────────────────────────────────────────
|
||
|
||
function bindEditForm(form) {
|
||
var submitButton = form.querySelector('#compose-submit');
|
||
var feedback = form.querySelector('.js-aksrt-action-feedback');
|
||
var ajaxUrl = form.getAttribute('data-ajax');
|
||
var nonce = form.getAttribute('data-nonce');
|
||
var topicId = form.getAttribute('data-topic-id');
|
||
|
||
if (!submitButton || !ajaxUrl || !nonce || !topicId) return;
|
||
|
||
form.addEventListener('submit', function (event) {
|
||
event.preventDefault();
|
||
|
||
var title = form.querySelector('#compose-title');
|
||
var content = getEditorContent();
|
||
|
||
if (!title || !title.value.trim() || !content.trim()) {
|
||
setFeedback(feedback, '标题和内容不能为空。', 'is-error');
|
||
return;
|
||
}
|
||
|
||
submitButton.disabled = true;
|
||
setFeedback(feedback, '正在保存…', 'is-loading');
|
||
|
||
var data = new FormData(form);
|
||
data.set('content', content);
|
||
data.append('action', 'aksrt_forum_edit_topic');
|
||
data.append('_nonce', nonce);
|
||
data.append('topic_id', topicId);
|
||
|
||
fetch(ajaxUrl, {
|
||
method: 'POST',
|
||
body: data,
|
||
credentials: 'same-origin',
|
||
}).then(function (r) { return r.json(); }).then(function (payload) {
|
||
if (!payload.success) {
|
||
throw new Error((payload.data && payload.data.message) || '保存失败');
|
||
}
|
||
if (payload.data && payload.data.redirect) {
|
||
window.location.href = payload.data.redirect;
|
||
return;
|
||
}
|
||
setFeedback(feedback, payload.data.message || '已保存', 'is-success');
|
||
submitButton.disabled = false;
|
||
}).catch(function (error) {
|
||
setFeedback(feedback, error.message || '保存失败', 'is-error');
|
||
submitButton.disabled = false;
|
||
});
|
||
});
|
||
}
|
||
|
||
// ── §7.6 Forum comment engine ─────────────────────────────────────────
|
||
|
||
function bindForumCommentEngine() {
|
||
var section = document.getElementById('aksrt-forum-replies');
|
||
if (!section) return;
|
||
|
||
var topicId = section.dataset.topicId;
|
||
var nonce = section.dataset.nonce;
|
||
var list = section.querySelector('.js-aksrt-forum-replies-list');
|
||
var loadMore = section.querySelector('.js-aksrt-forum-load-more');
|
||
var currentSort = 'newest';
|
||
var currentAuthorOnly = false;
|
||
|
||
// Sort tabs
|
||
section.querySelectorAll('.aksrt-forum-replies__tab').forEach(function (tab) {
|
||
tab.addEventListener('click', function () {
|
||
section.querySelectorAll('.aksrt-forum-replies__tab').forEach(function (t) { t.classList.remove('is-active'); });
|
||
tab.classList.add('is-active');
|
||
currentSort = tab.dataset.sort || 'newest';
|
||
loadComments(1);
|
||
});
|
||
});
|
||
|
||
// Author-only toggle
|
||
var authorToggle = section.querySelector('.aksrt-forum-replies__author-toggle');
|
||
if (authorToggle) {
|
||
authorToggle.addEventListener('change', function () {
|
||
currentAuthorOnly = authorToggle.checked;
|
||
loadComments(1);
|
||
});
|
||
}
|
||
|
||
// Load more button
|
||
if (loadMore) {
|
||
loadMore.addEventListener('click', function () {
|
||
var page = parseInt(loadMore.dataset.page, 10) || 1;
|
||
loadComments(page + 1, true);
|
||
});
|
||
}
|
||
|
||
function loadComments(page, append) {
|
||
var fd = new FormData();
|
||
fd.append('action', 'aksrt_forum_comments');
|
||
fd.append('nonce', nonce);
|
||
fd.append('topic_id', topicId);
|
||
fd.append('sort', currentSort);
|
||
fd.append('author_only', currentAuthorOnly ? '1' : '');
|
||
fd.append('page', page);
|
||
|
||
list.style.opacity = append ? '1' : '0.5';
|
||
|
||
fetch(window.aksrtForumGovernance ? window.aksrtForumGovernance.ajaxUrl : (window.ajaxurl || '/wp-admin/admin-ajax.php'), {
|
||
method: 'POST',
|
||
body: fd,
|
||
credentials: 'same-origin'
|
||
}).then(function (r) { return r.json(); })
|
||
.then(function (res) {
|
||
list.style.opacity = '1';
|
||
if (!res.success) return;
|
||
if (append) {
|
||
list.insertAdjacentHTML('beforeend', res.data.html);
|
||
} else {
|
||
list.innerHTML = res.data.html;
|
||
}
|
||
if (loadMore) {
|
||
loadMore.dataset.page = String(page);
|
||
loadMore.dataset.max = String(res.data.max_pages);
|
||
loadMore.closest('.aksrt-forum-replies__load-more').style.display =
|
||
res.data.has_more ? '' : 'none';
|
||
}
|
||
bindDynamicCommentActions(list);
|
||
}).catch(function () {
|
||
list.style.opacity = '1';
|
||
});
|
||
}
|
||
|
||
bindDynamicCommentActions(list);
|
||
}
|
||
|
||
function bindDynamicCommentActions(container) {
|
||
if (!container) return;
|
||
container.querySelectorAll('.js-aksrt-comment-like').forEach(bindCommentLike);
|
||
container.querySelectorAll('.js-aksrt-adopt-answer').forEach(bindAdoptButton);
|
||
container.querySelectorAll('.js-aksrt-comment-reply').forEach(bindCommentReply);
|
||
container.querySelectorAll('.js-aksrt-comment-top').forEach(bindCommentTop);
|
||
}
|
||
|
||
function bindCommentLike(btn) {
|
||
if (btn._likebound) return;
|
||
btn._likebound = true;
|
||
btn.addEventListener('click', function () {
|
||
var commentId = btn.dataset.commentId;
|
||
var active = btn.dataset.active === '1';
|
||
var newActive = !active;
|
||
|
||
btn.disabled = true;
|
||
fetch(window.aksrtForumGovernance ? window.aksrtForumGovernance.restUrl + 'aksrt/v1/comment/like' : '/wp-json/aksrt/v1/comment/like', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'X-WP-Nonce': window.aksrtForumGovernance ? window.aksrtForumGovernance.restNonce : ''
|
||
},
|
||
body: JSON.stringify({ comment_id: parseInt(commentId, 10), active: newActive }),
|
||
credentials: 'same-origin'
|
||
}).then(function (r) { return r.json(); })
|
||
.then(function (res) {
|
||
btn.disabled = false;
|
||
if (!res.success && !res.data) return;
|
||
var data = res.data || res;
|
||
btn.dataset.active = data.active ? '1' : '0';
|
||
btn.classList.toggle('is-active', !!data.active);
|
||
var icon = btn.querySelector('i');
|
||
if (icon) {
|
||
icon.className = data.active ? 'fas fa-thumbs-up' : 'far fa-thumbs-up';
|
||
}
|
||
var count = btn.querySelector('.aksrt-forum-reply__like-count');
|
||
if (count) {
|
||
count.textContent = data.count > 0 ? String(data.count) : '';
|
||
}
|
||
}).catch(function () { btn.disabled = false; });
|
||
});
|
||
}
|
||
|
||
function bindCommentReply(btn) {
|
||
if (btn._replybound) return;
|
||
btn._replybound = true;
|
||
btn.addEventListener('click', function () {
|
||
var commentId = btn.dataset.commentId;
|
||
var author = btn.dataset.author || '';
|
||
var form = document.querySelector('.aksrt-forum-topic__reply-form');
|
||
if (!form) return;
|
||
var textarea = form.querySelector('textarea[name="comment"]');
|
||
if (!textarea) return;
|
||
// Set reply parent
|
||
var parentInput = form.querySelector('input[name="comment_parent"]');
|
||
if (!parentInput) {
|
||
parentInput = document.createElement('input');
|
||
parentInput.type = 'hidden';
|
||
parentInput.name = 'comment_parent';
|
||
form.querySelector('form').appendChild(parentInput);
|
||
}
|
||
parentInput.value = commentId;
|
||
textarea.placeholder = '@' + author + ' ';
|
||
textarea.focus();
|
||
form.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||
});
|
||
}
|
||
|
||
function bindCommentTop(btn) {
|
||
if (btn._topbound) return;
|
||
btn._topbound = true;
|
||
btn.addEventListener('click', function () {
|
||
var commentId = btn.dataset.commentId;
|
||
var currentLevel = parseInt(btn.dataset.level, 10) || 0;
|
||
var newLevel = currentLevel > 0 ? 0 : 1;
|
||
|
||
btn.disabled = true;
|
||
var section = document.getElementById('aksrt-forum-replies');
|
||
var nonce = section ? section.dataset.nonce : '';
|
||
|
||
var fd = new FormData();
|
||
fd.append('action', 'aksrt_forum_comment_top');
|
||
fd.append('nonce', nonce);
|
||
fd.append('comment_id', commentId);
|
||
fd.append('level', newLevel);
|
||
|
||
fetch(window.aksrtForumGovernance ? window.aksrtForumGovernance.ajaxUrl : (window.ajaxurl || '/wp-admin/admin-ajax.php'), {
|
||
method: 'POST',
|
||
body: fd,
|
||
credentials: 'same-origin'
|
||
}).then(function (r) { return r.json(); })
|
||
.then(function (res) {
|
||
btn.disabled = false;
|
||
if (res.success) {
|
||
btn.dataset.level = String(newLevel);
|
||
var icon = btn.querySelector('i');
|
||
btn.childNodes.forEach(function (n) {
|
||
if (n.nodeType === 3) n.textContent = newLevel > 0 ? ' 取消置顶' : ' 置顶';
|
||
});
|
||
// Reload comments to reflect pin ordering
|
||
var activeTab = section && section.querySelector('.aksrt-forum-replies__tab.is-active');
|
||
if (activeTab) activeTab.click();
|
||
}
|
||
}).catch(function () { btn.disabled = false; });
|
||
});
|
||
}
|
||
|
||
// ── §7.10 Forum home tab engine ──────────────────────────────────────
|
||
|
||
function bindForumHomeTabs() {
|
||
var nav = document.getElementById('aksrt-forum-home-tabs');
|
||
if (!nav) return;
|
||
|
||
var content = document.getElementById('aksrt-forum-home-content');
|
||
if (!content) return;
|
||
|
||
var nonce = nav.dataset.nonce || '';
|
||
var ajaxUrl = nav.dataset.ajaxUrl || (window.aksrtForumGovernance ? window.aksrtForumGovernance.ajaxUrl : '/wp-admin/admin-ajax.php');
|
||
|
||
nav.querySelectorAll('.aksrt-forum-home-tabs__btn').forEach(function (btn) {
|
||
btn.addEventListener('click', function () {
|
||
var tabType = btn.dataset.tabType;
|
||
nav.querySelectorAll('.aksrt-forum-home-tabs__btn').forEach(function (b) { b.classList.remove('is-active'); });
|
||
btn.classList.add('is-active');
|
||
loadHomeTab(tabType, 1);
|
||
});
|
||
});
|
||
|
||
// Load-more on home content
|
||
content.addEventListener('click', function (e) {
|
||
var moreBtn = e.target.closest('.js-aksrt-home-load-more');
|
||
if (!moreBtn) return;
|
||
var page = parseInt(moreBtn.dataset.page, 10) || 1;
|
||
var tabType = moreBtn.dataset.tab || 'synthesis';
|
||
loadHomeTab(tabType, page + 1, true, moreBtn);
|
||
});
|
||
|
||
function loadHomeTab(tabType, page, append, moreBtn) {
|
||
var fd = new FormData();
|
||
fd.append('action', 'aksrt_forum_home_tab');
|
||
fd.append('nonce', nonce);
|
||
fd.append('tab_type', tabType);
|
||
fd.append('page', page);
|
||
|
||
if (!append) {
|
||
content.style.opacity = '0.5';
|
||
}
|
||
if (moreBtn) moreBtn.disabled = true;
|
||
|
||
fetch(ajaxUrl, { method: 'POST', body: fd, credentials: 'same-origin' })
|
||
.then(function (r) { return r.json(); })
|
||
.then(function (res) {
|
||
content.style.opacity = '1';
|
||
if (!res.success) return;
|
||
|
||
if (res.data.type === 'plate') {
|
||
// Plate tab — reload the whole page to get server-rendered board grid
|
||
window.location.href = window.location.pathname + '?forum_tab=plate';
|
||
return;
|
||
}
|
||
|
||
if (append) {
|
||
var list = content.querySelector('.js-aksrt-home-topic-list');
|
||
if (list) {
|
||
list.insertAdjacentHTML('beforeend', res.data.html);
|
||
}
|
||
if (moreBtn) {
|
||
moreBtn.disabled = false;
|
||
moreBtn.dataset.page = String(page);
|
||
if (!res.data.has_more) {
|
||
moreBtn.closest('.aksrt-forum-home__load-more').style.display = 'none';
|
||
}
|
||
}
|
||
} else {
|
||
var html = '<div class="aksrt-forum-topics__list js-aksrt-home-topic-list">' + res.data.html + '</div>';
|
||
if (res.data.has_more) {
|
||
html += '<div class="aksrt-forum-home__load-more">'
|
||
+ '<button type="button" class="aksrt-forum-replies__more-btn js-aksrt-home-load-more" data-page="1" data-max="' + res.data.max_pages + '" data-tab="' + tabType + '">'
|
||
+ '<i class="fas fa-chevron-down"></i> 加载更多</button></div>';
|
||
}
|
||
content.innerHTML = html;
|
||
}
|
||
}).catch(function () {
|
||
content.style.opacity = '1';
|
||
if (moreBtn) moreBtn.disabled = false;
|
||
});
|
||
}
|
||
}
|
||
|
||
|
||
function bindBoardSortTabs() {
|
||
var root = document.querySelector('.aksrt-forum-board[data-plate-id], .aksrt-forum-board[data-board-id]');
|
||
if (!root) return;
|
||
var list = root.querySelector('.js-aksrt-board-topic-list');
|
||
var tabs = root.querySelectorAll('.js-aksrt-board-sort-tab');
|
||
if (!list || !tabs.length) return;
|
||
|
||
var plateId = root.getAttribute('data-plate-id') || '';
|
||
var boardId = root.getAttribute('data-board-id') || '';
|
||
var nonce = root.getAttribute('data-nonce') || (window.aksrtForumGovernance && aksrtForumGovernance.publicNonce) || (window.aksrtData && aksrtData.nonce) || '';
|
||
var ajaxUrl = (window.aksrtForumGovernance && aksrtForumGovernance.ajaxUrl) || (window.aksrtData && aksrtData.ajaxUrl) || '';
|
||
|
||
function loadSort(sort, pushUrl) {
|
||
if (!ajaxUrl) return;
|
||
list.style.opacity = '0.55';
|
||
var fd = new FormData();
|
||
fd.append('action', 'aksrt_forum_board_topics');
|
||
fd.append('nonce', nonce);
|
||
fd.append('page', '1');
|
||
fd.append('orderby', sort);
|
||
if (plateId) fd.append('plate_id', plateId);
|
||
if (boardId) fd.append('board_id', boardId);
|
||
|
||
fetch(ajaxUrl, { method: 'POST', body: fd, credentials: 'same-origin' })
|
||
.then(function (r) { return r.json(); })
|
||
.then(function (res) {
|
||
list.style.opacity = '1';
|
||
if (!res || !res.success) return;
|
||
list.innerHTML = res.data.html || '';
|
||
root.setAttribute('data-active-sort', sort);
|
||
tabs.forEach(function (t) {
|
||
t.classList.toggle('is-active', (t.getAttribute('data-sort') || '') === sort);
|
||
});
|
||
if (pushUrl && window.history && history.replaceState) {
|
||
try {
|
||
var u = new URL(window.location.href);
|
||
u.searchParams.set('forum_sort', sort);
|
||
history.replaceState({}, '', u.toString());
|
||
} catch (e) {}
|
||
}
|
||
})
|
||
.catch(function () { list.style.opacity = '1'; });
|
||
}
|
||
|
||
tabs.forEach(function (tab) {
|
||
tab.addEventListener('click', function (e) {
|
||
e.preventDefault();
|
||
var sort = tab.getAttribute('data-sort') || 'date';
|
||
if (sort === (root.getAttribute('data-active-sort') || '')) return;
|
||
loadSort(sort, true);
|
||
});
|
||
});
|
||
}
|
||
|
||
function boot() {
|
||
var composeForm = document.querySelector('.js-aksrt-forum-compose-form');
|
||
if (composeForm) {
|
||
bindComposeToolbar(composeForm);
|
||
bindComposeVoteToggle(composeForm);
|
||
bindComposeCoverToggle(composeForm);
|
||
bindComposeVisibilityToggle(composeForm);
|
||
bindComposeDraft(composeForm);
|
||
bindComposeSubmit(composeForm);
|
||
bindRemoteSelects(composeForm);
|
||
bindTagInputs(composeForm);
|
||
bindTitleCounter(composeForm);
|
||
bindDraftUI();
|
||
}
|
||
|
||
var editForm = document.querySelector('.js-aksrt-forum-edit-form');
|
||
if (editForm) {
|
||
bindComposeVoteToggle(editForm);
|
||
bindComposeCoverToggle(editForm);
|
||
bindComposeVisibilityToggle(editForm);
|
||
bindRemoteSelects(editForm);
|
||
bindTagInputs(editForm);
|
||
bindTitleCounter(editForm);
|
||
bindEditForm(editForm);
|
||
}
|
||
|
||
document.querySelectorAll('.js-aksrt-moderator-apply-form').forEach(bindModeratorApplyForm);
|
||
document.querySelectorAll('.js-aksrt-topic-vote-form').forEach(bindVoteForm);
|
||
document.querySelectorAll('.js-aksrt-topic-moderation-form').forEach(bindModerationForm);
|
||
document.querySelectorAll('.js-aksrt-topic-action').forEach(bindQuickTopicAction);
|
||
document.querySelectorAll('.js-aksrt-topic-favorite').forEach(bindFavoriteButton);
|
||
document.querySelectorAll('.js-aksrt-topic-score').forEach(bindScoreButton);
|
||
document.querySelectorAll('.js-aksrt-adopt-answer').forEach(bindAdoptButton);
|
||
document.querySelectorAll('.js-aksrt-unlock-topic').forEach(bindUnlockButton);
|
||
document.querySelectorAll('.js-aksrt-follow-plate').forEach(bindFollowPlateButton);
|
||
bindForumCommentEngine();
|
||
bindForumHomeTabs();
|
||
bindBoardSortTabs();
|
||
document.querySelectorAll('.js-aksrt-edit-plate').forEach(bindEditPlateButton);
|
||
document.querySelectorAll('.js-aksrt-delete-plate').forEach(bindDeletePlateButton);
|
||
var reportModal = document.querySelector('#aksrt-report-modal');
|
||
if (reportModal) {
|
||
bindReportModal(reportModal);
|
||
}
|
||
}
|
||
|
||
if (document.readyState === 'loading') {
|
||
document.addEventListener('DOMContentLoaded', boot);
|
||
} else {
|
||
boot();
|
||
}
|
||
})();
|
||
|