Files
wordpress-theme-aksrt/assets/js/forum-governance.js
T
kate522 cf6ad0e972 feat(forum,admin): plate follow-pay MVP, sales column, order type tabs
Wire paid plate follow (admin meta + points/balance purchase + AJAX),
re-check plate gate on topics, post list sales column, and order type
subtabs; update gap matrix and admin IA map.
2026-07-15 11:00:36 +08:00

1581 lines
68 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
(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 bindPurchaseButton(button) {
button.addEventListener('click', function () {
var topicId = parseInt(button.getAttribute('data-topic-id') || '0', 10);
var price = button.getAttribute('data-price') || '0';
var isFree = button.getAttribute('data-free') === '1';
var feedback = button.parentElement ? button.parentElement.querySelector('.js-aksrt-action-feedback') : null;
if (!topicId) {
return;
}
var confirmMsg = isFree
? '确认使用 VIP 免费解锁此主题?'
: ('确认使用余额支付 ¥' + price + ' 购买此主题?');
if (!window.confirm(confirmMsg)) {
return;
}
button.disabled = true;
setFeedback(feedback, isFree ? '正在解锁…' : '正在支付…', 'is-loading');
var data = new FormData();
data.append('action', 'aksrt_forum_purchase_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) {
var confirmMsg = '确认付费关注该版块?';
if (payHint && payHint.is_free) {
confirmMsg = '确认使用 VIP 免费关注该版块?';
} else if (payHint) {
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) {
throw new Error((payload.data && payload.data.message) || '支付失败');
}
var res = payload.data || {};
button.setAttribute('data-followed', '1');
button.classList.add('is-followed');
var label = button.querySelector('span') || button;
if (button.querySelector('i') && button.childNodes.length) {
// keep icon, replace trailing text via last text-ish content
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 = '&times;';
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-purchase-topic').forEach(bindPurchaseButton);
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();
}
})();