feat(single): align author bar follow and reward actions with the site flows
- guests get the sign-in trigger instead of a redirect to the login page, for both follow and wallet reward controls - follow requests swap the label for an inline loader and block a second submit; the followed state uses the .actived hook - follower counts sync through data-follow-count on the user homepage (the previous selector matched nothing) and only for the viewed profile - reward button uses the secondary action colour; the reward template is only rendered for signed-in visitors - drop the unused author-hero aria-disabled rule and stale wording in the touched comments Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
8ad5ef9aff
commit
d40906b4a3
13 files changed
+148
-56
No files matched your search
+74
-27
@@ -6,68 +6,113 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var CONFIG = window.jioData || {};
|
||||
var API_ROOT = (function () {
|
||||
var data = window.jioData || {};
|
||||
var raw = data.apiUrl || data.restUrl || data.rest_url || '/index.php?rest_route=/jio/v1';
|
||||
var raw = CONFIG.apiUrl || CONFIG.restUrl || CONFIG.rest_url || '/index.php?rest_route=/jio/v1';
|
||||
return String(raw).replace(/\/$/, '');
|
||||
})();
|
||||
var NONCE = (window.jioData && window.jioData.restNonce) || '';
|
||||
var NONCE = CONFIG.restNonce || '';
|
||||
|
||||
function buttonsFor(userId) {
|
||||
return Array.prototype.slice.call(document.querySelectorAll('[data-jio-follow="' + userId + '"]'));
|
||||
}
|
||||
|
||||
function setLoading(buttons, loading) {
|
||||
buttons.forEach(function (button) {
|
||||
button.disabled = loading;
|
||||
button.classList.toggle('is-loading', loading);
|
||||
});
|
||||
function notify(message, type) {
|
||||
if (typeof window.notyf !== 'function') return;
|
||||
window.notyf(message, type || 'info');
|
||||
}
|
||||
|
||||
/** 站点登录弹窗由 auth.js 的全局委托接管,这里只点一下触发器。 */
|
||||
function openLoginModal() {
|
||||
var trigger = document.querySelector('.signin-loader') ||
|
||||
document.querySelector('[data-jio-auth-required]') ||
|
||||
document.querySelector('#nav-login-btn');
|
||||
if (trigger) trigger.click();
|
||||
}
|
||||
|
||||
/** 待发送态:按钮置灰不可重复提交,文案换成行内加载点。 */
|
||||
function setPending(button, pending) {
|
||||
var label = button.querySelector('[data-jio-follow-label]');
|
||||
if (pending) {
|
||||
button.setAttribute('disabled', '');
|
||||
button.setAttribute('aria-disabled', 'true');
|
||||
if (label) {
|
||||
label.dataset.jioFollowLabel = label.textContent;
|
||||
label.innerHTML = '<i class="loading zts"></i>';
|
||||
}
|
||||
return;
|
||||
}
|
||||
button.removeAttribute('disabled');
|
||||
button.removeAttribute('aria-disabled');
|
||||
if (label && label.dataset.jioFollowLabel !== undefined) {
|
||||
label.textContent = label.dataset.jioFollowLabel;
|
||||
delete label.dataset.jioFollowLabel;
|
||||
}
|
||||
}
|
||||
|
||||
function updateButton(button, isFollowing) {
|
||||
var icon = button.querySelector('i');
|
||||
var label = button.querySelector('[data-jio-follow-label]');
|
||||
if (!label) return;
|
||||
|
||||
button.classList.toggle('is-following', isFollowing);
|
||||
button.classList.toggle('actived', isFollowing);
|
||||
var icon = button.querySelector('i');
|
||||
if (icon) {
|
||||
icon.className = isFollowing ? 'fa fas fa-heart em09' : 'fa far fa-heart em09';
|
||||
var sizeClass = /\bem09\b/.test(icon.className) ? ' em09' : '';
|
||||
icon.className = (isFollowing ? 'fa fas fa-heart' : 'fa far fa-heart') + sizeClass;
|
||||
}
|
||||
label.textContent = isFollowing ? '已关注' : '关注';
|
||||
label.textContent = isFollowing
|
||||
? button.getAttribute('data-jio-follow-ok') || '已关注'
|
||||
: button.getAttribute('data-jio-follow-text') || '关注';
|
||||
delete label.dataset.jioFollowLabel;
|
||||
button.title = isFollowing ? '点击取消关注' : '关注该用户';
|
||||
}
|
||||
|
||||
function updateFollowerCount(count) {
|
||||
var countEl = document.querySelector('.jio-user-home__stat-value[data-followers]');
|
||||
if (countEl && count !== undefined) {
|
||||
countEl.textContent = count;
|
||||
}
|
||||
/** 关注数只在浏览被关注者本人的主页时同步,避免改到别人的粉丝数。 */
|
||||
function updateFollowerCount(targetUserId, count) {
|
||||
if (count === undefined || count === null) return;
|
||||
var scope = document.querySelector('.dashboard[data-user-id="' + targetUserId + '"]');
|
||||
if (!scope) return;
|
||||
scope.querySelectorAll('[data-follow-count="followers"]').forEach(function (node) {
|
||||
node.textContent = count;
|
||||
});
|
||||
}
|
||||
|
||||
// 全局 document 委托只绑定一次(模块顶层执行)。
|
||||
document.addEventListener('click', function (event) {
|
||||
var button = event.target.closest('[data-jio-follow]');
|
||||
if (!button) return;
|
||||
event.preventDefault();
|
||||
|
||||
var targetUserId = parseInt(button.getAttribute('data-jio-follow'), 10);
|
||||
if (!targetUserId || button.disabled) return;
|
||||
if (!targetUserId || button.hasAttribute('disabled')) return;
|
||||
|
||||
var matchingButtons = buttonsFor(targetUserId);
|
||||
setLoading(matchingButtons, true);
|
||||
matchingButtons.forEach(function (matchingButton) {
|
||||
setPending(matchingButton, true);
|
||||
});
|
||||
|
||||
fetch(API_ROOT + '/follow/toggle', {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-WP-Nonce': NONCE,
|
||||
},
|
||||
body: JSON.stringify({ target_user_id: targetUserId }),
|
||||
})
|
||||
.then(function (response) { return response.json(); })
|
||||
.then(function (response) {
|
||||
// 会话失效时直接拉起登录弹窗,不再额外弹错误提示。
|
||||
if (response.status === 401 || response.status === 403) {
|
||||
openLoginModal();
|
||||
return null;
|
||||
}
|
||||
return response.json().catch(function () {
|
||||
throw new Error('操作失败');
|
||||
});
|
||||
})
|
||||
.then(function (result) {
|
||||
if (!result) return;
|
||||
if (!result.success || !result.data) {
|
||||
notyf(result.message || '操作失败', 'danger');
|
||||
notify(result.message || '操作失败', 'danger');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -75,19 +120,21 @@
|
||||
matchingButtons.forEach(function (matchingButton) {
|
||||
updateButton(matchingButton, isFollowing);
|
||||
});
|
||||
updateFollowerCount(result.data.follower_count);
|
||||
updateFollowerCount(targetUserId, result.data.follower_count);
|
||||
|
||||
if (!isFollowing) {
|
||||
var managementItem = button.closest('.uc-follow-management__item');
|
||||
if (managementItem) managementItem.remove();
|
||||
}
|
||||
notyf(isFollowing ? '关注成功' : '已取消关注', 'success');
|
||||
notify(isFollowing ? '已关注此用户' : '已取消关注此用户', 'success');
|
||||
})
|
||||
.catch(function () {
|
||||
notyf('网络错误,请重试', 'danger');
|
||||
.catch(function (error) {
|
||||
notify((error && error.message) || '网络错误,请重试', 'danger');
|
||||
})
|
||||
.finally(function () {
|
||||
setLoading(matchingButtons, false);
|
||||
matchingButtons.forEach(function (matchingButton) {
|
||||
setPending(matchingButton, false);
|
||||
});
|
||||
});
|
||||
});
|
||||
})();
|
||||
Reference in new issue
Block a user